请问 Python 3.11 版本是对线程安全做了什么更改吗?

2023-08-17 07:39:06 +08:00
 ohayoo
import threading

num = 0


def add():
    global num
    for i in range(10_000_000):
        num += 1


def sub():
    global num
    for i in range(10_000_000):
        num -= 1


if __name__ == "__main__":

    add_t = threading.Thread(target=add)
    sub_t = threading.Thread(target=sub)

    add_t.start()
    sub_t.start()

    add_t.join()
    sub_t.join()

    print("num result : %s" % num)

昨天偶然发现这份代码在 3.11.3 中它居然输出 0 ,一度以为自己写错了,抱着不信邪的态度,又搞了个 Python 3.9.7 的环境试了下,果然还是符合自己预期,输出不为 0

想问下 3.11 版本中是做了什么修改吗?

4352 次点击
所在节点    Python
46 条回复
chaleaochexist
2023-08-17 17:47:39 +08:00
正常开发 都会加锁的.
mikewang
2023-08-18 03:16:44 +08:00
看起来是一些优化让这里的 += -= 变为了原子操作,不过不能依赖这种特性,毕竟 Python 标准文档中没有说明过他们是原子的,以后也可能随时变回非原子操作。
julyclyde
2023-08-18 19:57:49 +08:00
@sujin190 从+= 和-=的语义来说,就不该断在中间啊
没想到这么多年了才确保了不会断在中间
sujin190
2023-08-18 21:17:19 +08:00
@julyclyde 想多了,汇编都不是,这个和 cpu 独立核心对应的是独立栈帧,就想 cpu 计算指令只能运行在寄存器,Python 对应的则是计算指令只能运行在栈帧上,多线程下独立寄存器和独立栈帧问题自然是一样的了,而且各种语言都是这么设计的,这是效率和准确性取舍没啥问题,不过相对于 gcc 对寄存器使用深度各种优化,Python 编译器对栈帧使用的优化说实话真不咋滴
RageBubble
2023-08-22 14:42:53 +08:00
@deplivesb 不过看你的截图中,3.10 后的不是已经将 INPLACE_ADD 替换为了 BINARY_OP ,更准确的说法是不是“3.10 以后,BINARY_OP 操作之后 GIL 不再会主动检测中断”?
deplivesb
2023-08-22 15:52:32 +08:00
@RageBubble 看 #25

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/965954

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX