Python 3.10 和其他版本的线程差异

Python threads difference for 3.10 and others

对于一些简单的线程相关代码,即:

import threading


a = 0
threads = []


def x():
    global a
    for i in range(1_000_000):
        a += 1


for _ in range(10):
    thread = threading.Thread(target=x)
    threads.append(thread)
    thread.start()


for thread in threads:
    thread.join()


print(a)
assert a == 10_000_000

根据 Python 版本,我们得到了不同的行为。

对于 3.10,输出为:

❯ python3.10 b.py
10000000

对于 3.9,输出为:

❯ python3.9 b.py
2440951
Traceback (most recent call last):
  File "/Users/romka/t/threads-test/b.py", line 24, in <module>
    assert a == 10_000_000
AssertionError

由于我们没有获得任何锁,对我来说,3.9 的结果是显而易见的,也是意料之中的。问题是 3.10 为什么以及如何得到“正确”的结果,而不应该?

我正在查看 Python 3.10 的变更日志,没有任何与线程或 GIL 相关的内容可以带来这样的结果。

An answer from a core developer:

Unintended consequence of Mark Shannon's change that refactors fast opcode dispatching: https://github.com/python/cpython/commit/4958f5d69dd2bf86866c43491caf72f774ddec97 -- the INPLACE_ADD opcode no longer uses the "slow" dispatch path that checks for interrupts and such.