Python内置容器线程安全吗?

68 投票
4 回答
43592 浏览
提问于 2025-04-15 19:03

我想知道Python里面的内置容器(比如列表、向量、集合等等)是否是线程安全的?还是说我需要为我的共享变量实现一个锁定和解锁的环境?

4 个回答

7

只要你在C代码中没有关闭线程的全局解释器锁(GIL),它们就是线程安全的。

12

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

举个例子:

如果有两个线程同时想从一个只有一个项目的列表中用 pop() 方法取出东西,一个线程会成功取到这个项目,而另一个线程就会遇到 IndexError 错误

像这样的代码是不安全的,可能会出问题

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

你应该这样写

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

在Python中,你需要为所有会被修改的共享变量自己实现锁定。你不需要担心那些不会被修改的变量(也就是说,多个线程同时读取是可以的),所以不可变类型(比如 frozensettuplestr)大概是安全的,但加个锁也没坏处。对于那些你会改变的东西,比如 listsetdict 以及大多数其他对象,你应该有自己的锁定机制(虽然对这些大多数进行就地操作是可以的,但多线程可能会导致非常棘手的错误——所以最好还是实现锁定,这其实很简单)。

顺便说一下,不知道你知不知道,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及之前的版本中没有这个功能,所以你需要把 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)

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

撰写回答