2010-04-12 78 views

回答

54

让我们来看看:

>>> 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 
4

是的,是的,它会。

I stand corrected

Kragen Sitaker 写道:使用成语

spam, eggs = eggs, spam 

获得一个线程安全的交换

有人推荐。这真的有用吗? (...)
因此,如果此线程失去第一LOAD_FAST
最后STORE_FAST之间的任何控制,数值可以得到存储在由另一个线程
为“B”,这将被丢失。没有任何东西能够保持这种发生,是吗?

没有。一般来说,即使简单的 分配也必然是线程安全的 ,因为执行分配可能会在对象 上调用特殊方法,这些方法本身可能需要操作数 。 希望对象 将内部锁定它的 “状态”值,但这并不总是 的情况。

但它确实在特定 应用什么 “线程安全”是指决定,因为我的脑海里有 是这样 安全的粒度的多层次,所以很难谈 “线程安全”。关于唯一的东西 Python解释器将 免费提供给您的是,即使使用本地线程,内置的 数据类型也应该从内部的 损坏中安全。 换句话说,如果两个线程都 a=0xffa=0xff00,一个最终会 与一个或另一个,但不是 意外0xffff如可能在其他一些语言 可能的,如果一个 不受保护。

随着中说,的Python也趋于 执行这样的方式,你可以 逃脱一个可怕的很多不正规的 锁定,如果你愿意 生活在边缘了一下,有 暗示对实际使用的 对象的依赖关系。沿着这些线在 c.l中有一个体面的 讨论。一会儿回来 - 搜索 groups.google.com中的“Critical 部分和互斥体”线程在 之间。

就个人而言,我显式地锁定在任何多线程应用程序共享 状态(或使用的构建体设计用于 交换共享信息正确 之间线程,如Queue.Queue) 。到 我的脑海里它是最好的保护 反对维护和演变下来 的道路。

- - David

+1

为什么? GIL?反汇编不建议原子性(见@ jemfinch的答案)。 – kennytm 2010-04-12 15:17:44

+0

(顺便说一下,上面的评论*不是一个反问的问题。) – kennytm 2010-04-12 15:26:06

+0

@Kenny:这是我的部分误解,因为tuple解包是如何在低级别上工作的。 – voyager 2010-04-12 15:33:02

相关问题