列表是否是线程安全的?

lem*_*ant 137 python multithreading list python-multithreading python-3.x

我注意到经常建议使用具有多个线程的队列,而不是列表和.pop().这是因为列表不是线程安全的,还是出于其他原因?

Tho*_*ers 163

列表本身是线程安全的.在CPython中,GIL可以防止对它们进行并发访问,而其他实现则会为其列表实现使用细粒度锁或同步数据类型.但是,虽然列表本身不会因同时访问的尝试而损坏,但列表的数据不受保护.例如:

L[0] += 1
Run Code Online (Sandbox Code Playgroud)

如果另一个线程执行相同的操作,则不保证实际将L [0]增加1,因为+=它不是原子操作.(非常,很少有Python中的操作实际上是原子的,因为它们中的大多数都可以导致调用任意Python代码.)您应该使用队列,因为如果您只使用不受保护的列表,您可能会因为种族而获取或删除错误的项目条件.

  • 所有Python对象都具有相同类型的线程安全性 - 它们本身不会损坏,但它们的数据可能会损坏.collections.deque是Qu​​eue.Queue对象背后的东西.如果你从两个线程访问东西,你真的应该使用Queue.Queue对象.真. (20认同)
  • lemiant,deque是线程安全的.从Fluent Python的第2章开始:"类collections.deque是一个线程安全的双端队列,设计用于快速插入和从两端移除.[...] append和popleft操作是原子的,所以deque是安全的在多线程应用程序中用作LIFO队列而无需使用锁." (9认同)
  • 双端队列也是线程安全的吗?看起来更适合我的使用。 (2认同)
  • 这是关于CPython还是关于Python的答案?Python本身的答案是什么? (2认同)

dot*_*hen 80

为了澄清托马斯的优秀答案中的一点,应该提到的append() 线程安全.

这是因为一旦我们写入数据,就不会担心被读取的数据会在同一个地方.该操作不读取数据,只将数据写入列表.append()

  • 怎么样'删除'? (4认同)
  • dotancohen的观点是`L [0] + = x`将在`L`上执行`__getitem__`然后在'L`上执行`__setitem__` - 如果`L`支持`__iadd__`它将执行的操作在对象接口上有点不同,但在python解释器级别的`L`上仍然有两个单独的操作(你将在编译的字节码中看到它们).`append`是在字节码中的单个方法调用中完成的. (2认同)
  • 赞!所以我可以连续追加一个线程并弹出另一个线程吗? (2认同)

Jon*_*han 36

这是一个全面但非详尽list操作示例列表,以及它们是否是线程安全的.希望能得到关于答案obj in a_list的语言结构在这里.

  • 一百万年来我从来没有想到过 list.sort() 是原子的,我对此表示怀疑,但我测试了它,这是真的,一旦一个线程开始对包含 1e8 元素的巨大列表进行排序,它就会阻止所有其他线程访问列表。(我有另一个线程不断检索元素 0,并且在线程 A 排序时它挂起了几秒钟)。所以我猜这是真的,并在“pythong 3.9.1”中得到验证 (6认同)