32

参考以下链接:http ://docs.python.org/faq/library.html#what-kinds-of-global-value-mutation-are-thread-safe

我想知道以下是否:

(x, y) = (y, x)

将保证在 cPython 中是原子的。(x 和 y 都是 python 变量)

4

2 回答 2

58

让我们来看看:

>>> x = 1
>>> y = 2
>>> def swap_xy():
...   global x, y
...   (x, y) = (y, x)
... 
>>> dis.dis(swap_xy)
  3           0 LOAD_GLOBAL              0 (y)
              3 LOAD_GLOBAL              1 (x)
              6 ROT_TWO             
              7 STORE_GLOBAL             1 (x)
             10 STORE_GLOBAL             0 (y)
             13 LOAD_CONST               0 (None)
             16 RETURN_VALUE    

看起来它们不是原子的:x 和 y 的值可以由另一个线程在LOAD_GLOBAL字节码之间、在 之前或之后ROT_TWO以及在STORE_GLOBAL字节码之间进行更改。

如果你想原子地交换两个变量,你需要一个锁或一个互斥锁。

对于那些渴望经验证明的人:

>>> def swap_xy_repeatedly():
...   while 1:
...     swap_xy()
...     if x == y:
...       # If all swaps are atomic, there will never be a time when x == y.
...       # (of course, this depends on "if x == y" being atomic, which it isn't;
...       #  but if "if x == y" isn't atomic, what hope have we for the more complex
...       #  "x, y = y, x"?)
...       print 'non-atomic swap detected'
...       break
... 
>>> t1 = threading.Thread(target=swap_xy_repeatedly)
>>> t2 = threading.Thread(target=swap_xy_repeatedly)
>>> t1.start()
>>> t2.start()
>>> non-atomic swap detected
于 2010-04-12T15:16:24.533 回答
4

是的,是的,它会的。

我站得更正了

Kragen Sitaker 写道:

有人推荐使用成语

spam, eggs = eggs, spam

获得线程安全的交换。这真的有效吗?(...)
因此,如果此线程在第一个 LOAD_FAST
和最后一个 STORE_FAST 之间的任何地方失去控制,则另一个线程可能会将一个值存储
到“b”中,然后该值将丢失。没有什么可以阻止这种
情况发生,不是吗?

没有。通常,即使是简单的赋值也不一定是线程安全的,因为执行赋值可能会调用对象上的特殊方法,这些方法本身可能需要许多操作。 希望该对象将在内部锁定其“状态”值,但情况并非总是如此。

但这实际上取决于“线程安全”在特定应用程序中的含义,因为在我看来,这种安全性有很多级别的粒度,因此很难谈论“线程安全”。Python 解释器将免费为您提供的唯一一件事是,即使使用本机线程,内置数据类型也应该免受内部损坏。换句话说,如果两个线程具有 a=0xffand a=0xff00, a 将以一个或另一个结束,但0xffff如果 a 不受保护,则不会像在其他一些语言中可能发生的那样意外。

话虽如此,Python 也倾向于以这样一种方式执行,如果您愿意稍微生活在边缘并且隐含依赖于实际使用的对象,那么您可以在没有正式锁定的情况下侥幸逃脱。不久前,在 clp 中进行了类似的讨论——在 groups.google.com 中搜索“关键部分和互斥锁”线程等。

就个人而言,我在任何多线程应用程序中显式锁定共享状态(或使用为在线程之间正确交换共享信息而设计的结构,例如)。Queue.Queue在我看来,这是防止维护和进化的最佳保护。

-- --大卫

于 2010-04-12T15:14:31.033 回答