2010-02-09 28 views

回答

39

您需要爲所有將在Python中修改的共享變量實現自己的鎖定。你不必擔心從不會被修改的變量(即併發讀取可以)讀取數據,所以不可變類型(frozenset,tuple,str)是,可能是安全的,但它不會受到傷害。對於你將要改變的東西 - list,set,dict和大多數其他對象,你應該有自己的鎖定機制(雖然就地操作對大多數這些都是可以的,但是線程會導致超級討厭的錯誤 - 你可能還會實現鎖定,這很容易)。

順便說一句,我不知道你是否知道這一點,但鎖定在Python很容易 - 創建一個threading.lock對象,然後你可以獲取/釋放它是這樣的:

import threading 
list1Lock = threading.Lock() 

with list1Lock: 
    # change or read from the list here 
# continue doing other stuff (the lock is released when you leave the with block) 

在Python 2.5中,請執行from __future__ import with_statement; Python的2.4和之前沒有這個,所以你會希望把採集()/釋放()調用try:...finally:塊:

​​

Some very good information about thread synchronization in Python

+12

我相信,對於之前沒有使用過線程鎖的人來說,應該注意的是鎖(在你的例子中,'list1Lock')應該在線程之間共享*,以便它能夠正常工作。兩個獨立的鎖,每個線程一個鎖,什麼都不會鎖,只會增加傻瓜的開銷。 – tzot 2010-02-18 08:44:53

+0

不應該是這樣: with list1Lock:#做東西 – 2011-05-20 08:09:49

+0

@ slack3r良好的調用! – 2011-05-20 17:59:55

3

只要您不禁用線程的C代碼中的GIL,它們就是線程安全的。

+5

這是CPython的實現細節,你不應該繼續。將來可能會有機會,其他實現也沒有。 – 2010-02-09 06:32:36

+0

格奧爾格 - 蟒蛇的這種方式阻止我。當8核心在桌面上變得常見時,不要介意所有會從Java程序中退出的錯誤 - 當GIL被移除並且多線程Python應用突然在8核心盒子上運行時會發生什麼? – Ben 2010-02-09 12:11:04

+3

如果他們不明白自己的代碼是否是線程安全的,那麼它不應該嚇倒任何人。 :) – Kylotan 2010-02-09 15:12:16

7

是的,但你仍然需要小心,當然

。例如:

如果兩個線程都從列表中只有一個項目競相pop(),一個線程將成功獲得該項目和其他將得到一個IndexError

這樣的代碼是不是線程安全的

if L: 
    item=L.pop() # L might be empty by the time this line gets executed 

你應該WR像這樣迭代它

try: 
    item=L.pop() 
except IndexError: 
    # No items left 
+5

我想彈出()是線程安全的,但我無法在文檔中的任何位置找到這個事實。在我把它作爲福音之前,有人能幫我找出這個說法嗎? – 2012-03-28 13:12:41

+0

真的嗎? list.pop()不是線程安全的?我看到另一篇文章宣稱相反。 http://effbot.org/pyfaq/what-kinds-of-global-value-mutation-are-thread-safe.htm – 2016-10-03 18:50:34

+0

@ Zhongjun'Mark'Jin他說它是線程安全的..但這並不意味着你不必考慮其他線程。如果一個線程彈出最後一個項目,然後另一個線程嘗試彈出,它會得到IndexError,正如他所說的。 – fantabolous 2016-12-07 05:46:27