Python内置容器是否是线程安全的?

Pho*_*ong 52 python thread-safety

我想知道Python内置容器(list,vector,set ...)是否是线程安全的?或者我是否需要为共享变量实现锁定/解锁环境?

Dan*_*l G 46

您需要为将在Python中修改的所有共享变量实现自己的锁定.你不必担心从不会被修改的变量读(即并发读取都OK了),所以稳定的类型(frozenset,tuple,str)都可能是安全的,但它不会伤害.对于东西你要有所改变- ,list,set,dict和大多数其他的对象,你应该有自己的锁定机制(而就地操作都OK在大多数的这些,线程可以导致超级讨厌的错误-你还不如很好地实现锁定,这很容易).

顺便说一句,我不知道你是否知道这一点,但在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)
Run Code Online (Sandbox Code Playgroud)

在Python 2.5中,做from __future__ import with_statement; Python 2.4和之前没有这个,所以你需要将acquire()/ release()调用放在try:...finally:块中:

import threading
list1Lock = threading.Lock()

try:
    list1Lock.acquire()
    # change or read from the list here
finally:
    list1Lock.release()
# continue doing other stuff (the lock is released when you leave the with block)
Run Code Online (Sandbox Code Playgroud)

关于Python中线程同步的一些非常好的信息.

  • 我相信,对于之前没有使用过线程锁的人来说,应该注意锁(在你的例子中,`list1Lock`)应该在线程之间*共享*,以使其正常工作.两个独立的锁,每个线程一个,不会锁定任何东西,只是添加愚蠢的开销. (14认同)
  • “但是不会受伤”……无论是否必要。 (2认同)

Joh*_*ooy 10

是的,但你当然还需要小心

例如:

如果两个线程pop()从仅包含一个项目的列表中竞争,则一个线程将成功获取该项目,另一个线程将获得一个IndexError

像这样的代码不是线程安全的

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

你应该这样写

try:
    item=L.pop()
except IndexError:
    # No items left
Run Code Online (Sandbox Code Playgroud)

  • 我希望pop()是线程安全的,但我在文档中的任何地方都找不到这个事实.在我把它作为福音之前,有人可以帮助我提出这个主张吗? (6认同)
  • @Zhongjun'Mark'Jin 他说它是线程安全的……但这并不意味着您不必考虑其他线程。如果一个线程弹出最后一个项目,然后另一个线程也尝试弹出,它将得到 IndexError,正如他所说。 (2认同)

Ign*_*ams 5

只要您不在线程的C代码中禁用GIL,它们就是线程安全的。

  • 这是您不应该继续使用的CPython的实现细节。将来可能会碰碰运气,而其他实现则没有。 (5认同)
  • 如果他们不假装自己的代码显然不是线程安全的,那么它就不会吓到任何人。:) (3认同)
  • @PiotrDobrogost:GIL 并不存在于所有 Python 实现中。[python.org](http://wiki.python.org/moin/GlobalInterpreterLock):*Jython 和 IronPython 没有 GIL,可以充分利用多处理器系统。*此外,从长远来看,CPython 试图摆脱 GIL . (3认同)