2015-06-19 149 views
2

我有以下任務,我想通過多線程(python3)更快地完成任務。多線程使進程更慢

import threading, time 

q = [] 

def fill_list(): 
    global q 
    while True: 
     q.append(1) 
     if len(q) >= 1000000000: 
      return 

的第一主不使用多線程:

t1 = time.clock() 
fill_list() 
tend = time.clock() - t1 
print(tend) 

,並導致運行時間145秒。

第二調用兩個線程:

t1 = time.clock() 
thread1 = threading.Thread(target=fill_list, args=()) 
thread2 = threading.Thread(target=fill_list, args=()) 

thread1.start() 
thread2.start() 

thread1.join() 
thread2.join() 

tend = time.clock() - t1 
print(tend) 

這需要152秒來完成。

最後,我添加了第三個線程。

t1 = time.clock() 
thread1 = threading.Thread(target=fill_list, args=()) 
thread2 = threading.Thread(target=fill_list, args=()) 
thread3 = threading.Thread(target=fill_list, args=()) 

thread1.start() 
thread2.start() 
thread3.start() 

thread1.join() 
thread2.join() 
thread3.join() 

tend = time.clock() - t1 
print(tend) 

而這需要233秒才能完成。

很明顯,我添加的線程越多,處理所需的時間越長,但我不知道爲什麼。這是對多線程的基本誤解,還是我的代碼中存在一個錯誤,它只是多次重複執行任務,而不是對同一任務做出貢獻?

+2

你已經發現[GIL的(HTTPS://wiki.python .ORG /莫因/ GlobalInterpreterLock)。 – dano

回答

5

答案1和2

首先,你的任務是CPU綁定,並在Python進程只有一個線程可以在任何給定的時間(運行CPU密集型的Python代碼,這是由於全球口譯員鎖:https://wiki.python.org/moin/GlobalInterpreterLock)。由於切換線程需要花費相當多的CPU資源(並且線程數越多,需要付出的代價越多),程序不會加速:速度變慢。其次,無論您使用何種語言,您都需要修改多個線程中的一個對象(列表)。但爲了保證這不會破壞對象,訪問必須同步。換句話說,只有一個線程可能在任何給定時間修改它。 Python會自動執行它(部分歸功於前面提到的GIL),但是在另一個低級語言(如C++)中,您必須使用鎖定或冒內存損壞。

跨線程並行化任務的最佳方式是確保線程儘可能地孤立。如果他們訪問共享對象,那麼應該是只讀,並且跨線程寫入應該儘可能少地通過線程感知數據結構(如消息隊列)發生。

(這就是爲什麼像Erlang和Clojure的最高效的並行系統將如此高的重視不可改變的數據結構和消息傳遞)