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.
对于一些简单的线程相关代码,即:
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.