python 中变量交换保证是原子的吗?

发布于 2024-08-28 17:42:57 字数 336 浏览 1 评论 0原文

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

我想知道是否

(x, y) = (y, x)

可以保证 以下内容: cPython 中的原子。 (x和y都是python变量)

With reference to the following link: http://docs.python.org/faq/library.html#what-kinds-of-global-value-mutation-are-thread-safe

I wanted to know if the following:

(x, y) = (y, x)

will be guaranteed atomic in cPython. (x and y are both python variables)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

哭泣的笑容 2024-09-04 17:42:57

让我们看看:

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

Let's see:

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

It doesn't appear that they're atomic: the values of x and y could be changed by another thread between the LOAD_GLOBAL bytecodes, before or after the ROT_TWO, and between the STORE_GLOBAL bytecodes.

If you want to swap two variables atomically, you'll need a lock or a mutex.

For those desiring empirical proof:

>>> 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
微暖i 2024-09-04 17:42:57

是的,是的,会的。

我经修正。

克拉根·西塔克
写道:

<块引用>

有人推荐使用这个习语

垃圾邮件,鸡蛋 = 鸡蛋,垃圾邮件

获得线程安全的交换。这真的有效吗? (...)
因此,如果该线程在第一个 LOAD_FAST
之间的任何地方失去控制
最后一个 STORE_FAST,一个值可以由另一个线程存储
到“b”,然后就会丢失。没有任何东西可以保留这个
发生了,有吗?

不。一般来说,甚至不是一个简单的
赋值必然是线程安全的
因为执行任务可能
调用对象上的特殊方法
它们本身可能需要一个数字
的操作。 希望是对象
将内部锁定其
“状态”值,但这并不总是
案例。

但这实际上是由什么决定的
“线程安全”是指在特定的
应用程序,因为在我看来
此类的粒度有很多级别
安全性所以很难谈论
“线程安全”。关于唯一的一件事
Python 解释器将会
免费给你的是一个内置的
数据类型应该对内部安全
即使使用本机线程也会损坏。
换句话说,如果两个线程有
a=0xffa=0xff00,a 最终会出现
与其中之一,但不是
意外0xffff可能是
可能在其他一些语言中,如果
不受保护。

话虽如此,Python 也倾向于
以这样的方式执行,你可以
逃脱了很多没有
正式锁定,如果你愿意的话
生活有点边缘并且有
对实际情况的隐含依赖
使用中的对象
。有一个像样的
沿着这些思路进行讨论
不久前 clp - 搜索
groups.google.com 的“关键
部分和互斥体”线程之间
其他。

就个人而言,我明确锁定共享
状态(或使用设计用于
正确交换共享信息
在线程之间,例如 Queue.Queue)
在任何多线程应用程序中。到
我的想法是最好的保护
反对维护和进化下降
路。

--
-- 大卫

Yes, yes it will.

I stand corrected.

Kragen Sitaker
writes:

Someone recommended using the idiom

spam, eggs = eggs, spam

to get a thread-safe swap. Does this really work? (...)
So if this thread loses control anywhere between the first LOAD_FAST
and the last STORE_FAST, a value could get stored by another thread
into "b" which would then be lost. There isn't anything keeping this
from happening, is there?

Nope. In general not even a simple
assignment is necessarily thread safe
since performing the assignment may
invoke special methods on an object
which themselves may require a number
of operations. Hopefully the object
will have internally locked its
"state" values, but that's not always
the case.

But it's really dictated by what
"thread safety" means in a particular
application, because to my mind there
are many levels of granularity of such
safety so it's hard to talk about
"thread safety". About the only thing
the Python interpreter is going to
give you for free is that a built-in
data type should be safe from internal
corruption even with native threading.
In other words if two threads have
a=0xff and a=0xff00, a will end up
with one or the other, but not
accidentally 0xffff as might be
possible in some other languages if a
isn't protected.

With that said, Python also tends to
execute in such a fashion that you can
get away with an awful lot without
formal locking, if you're willing to
live on the edge a bit and have
implied dependencies on the actual
objects in use
. There was a decent
discussion along those lines here in
c.l.p a while back - search
groups.google.com for the "Critical
sections and mutexes" thread among
others.

Personally, I explicitly lock shared
state
(or use constructs designed for
exchanging shared information properly
amongst threads, such as Queue.Queue)
in any multi-threaded application. To
my mind it's the best protection
against maintenance and evolution down
the road.

--
-- David

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文