深圳专业做公司网站,浙江外发加工网,山乙建设公司网站,网站设计公司网站设计问题#xff1a;这份代码在 3.11.3 中它居然输出 0 #xff0c;一度以为自己写错了#xff0c;抱着不信邪的态度#xff0c;又搞了个 Python 3.9.7 的环境试了下#xff0c;果然还是符合自己预期#xff0c;输出不为 0#xff0c;想问下 3.11 版本中是做了什么修改吗这份代码在 3.11.3 中它居然输出 0 一度以为自己写错了抱着不信邪的态度又搞了个 Python 3.9.7 的环境试了下果然还是符合自己预期输出不为 0想问下 3.11 版本中是做了什么修改吗
import threadingnum 0def add():global numfor i in range(10_000_000):num 1def sub():global numfor i in range(10_000_000):num - 1if __name__ __main__:add_t threading.Thread(targetadd)sub_t threading.Thread(targetsub)add_t.start()sub_t.start()add_t.join()sub_t.join()print(num result : %s % num)
答案 首先在 Python 字节码执行的时候 GIL 并不是随时能在任意位置中断切换线程。只有在主动检测中断的地方才可能发生线程切换。这个是大前提 3.10 之前的版本中INPLACE_ADD 这个 opcode 之后 GIL 会去主动监测中断所以导致现成不安全。3.10 的代码中有一个提交https://github.com/python/cpython/commit/4958f5d69dd2bf86866c43491caf72f774ddec97 根据 T. Wouters 的 Twitter 描述 https://twitter.com/Yhg1s/status/1460935209059328000 这次提交修改了 INPLACE_ADD 之后主动监测中断的操作。使得 INPLACE_ADD 之后无论如何都不会发生线程切换因此虽然是两个 opcode 但是确实是线程安全。 因为字节码中的操作是两步 opcode 操作且 INPLACE_ADD 之后 GIL 会主动监测中断导致虽然加了但是没有重新赋值就切换到了别的线程上**。比如 A 线程 当前 num100 。1 之后 101 但是买没来得及重新赋值给 num GIL 切换了线程再 B 线程中 num 还是 100 -之后就是 99 但是这个线程却赋值给了 num 此时 num 就是 99 然后又且回了 A 线程**。结果线程将中断时候的 101 赋值给了 num 导致此时 num 变成了 101 就出现问题了 3.10 以后就不会出现这个问题了因为 INPLACE_ADD 操作之后 GIL 不再会主动检测中断意味着正常情况下执行完之后线程不会被切换而是正确执行了赋值给 num 的操作