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

  • 问题:这份代码在 3.11.3 中它居然输出 0 ,一度以为自己写错了,抱着不信邪的态度,又搞了个 Python 3.9.7 的环境试了下,果然还是符合自己预期,输出不为 0,想问下 3.11 版本中是做了什么修改吗?
python 复制代码
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)
  • 答案:
    1. 首先在 Python 字节码执行的时候 ,GIL 并不是随时能在任意位置中断切换线程。只有在主动检测中断的地方才可能发生线程切换。这个是大前提

    2. 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 ,但是确实是线程安全。

    3. 因为字节码中+=的操作是两步 opcode 操作,且 INPLACE_ADD 之后 GIL 会主动监测中断,导致虽然加了,但是没有重新赋值,就切换到了别的线程上**。比如 A 线程 当前 num=100 。+=1 之后 101 但是买没来得及重新赋值给 num ,GIL 切换了线程,再 B 线程中 num 还是 100 ,-=之后就是 99 ,但是这个线程却赋值给了 num ,此时 num 就是 99 然后又且回了 A 线程**。结果线程将中断时候的 101 赋值给了 num 导致此时 num 变成了 101 就出现问题了

    4. 3.10 以后就不会出现这个问题了,因为 INPLACE_ADD 操作之后 GIL 不再会主动检测中断,意味着正常情况下执行完+=之后线程不会被切换,而是正确执行了赋值给 num 的操作

相关推荐
刘悦的技术博客2 天前
MagicQuill,AI动态图像元素修改,AI绘图,需要40G的本地硬盘空间,12G显存可玩,Win11本地部署
ai·aigc·python3.11
follycat5 天前
ISCTF2024
java·网络·数据库·学习·网络安全·python3.11
fen_fen7 天前
Python3.11.9下载和安装
python3.11
壹屋安源11 天前
CentOS 安装 Python 3.11.9完整流程
python·centos·virtualenv·pip·python3.11
刘悦的技术博客1 个月前
MaskGCT,AI语音克隆大模型本地部署(Windows11),基于Python3.11,TTS,文字转语音
ai·tts·python3.11
Python_trys1 个月前
python3的语法及入门(近7000字,耐心看包全,看完记得点赞)!
开发语言·python·python3.11
我命由我123451 个月前
1.Python 引入(字面量、注释、变量、数据类型、数据类型转换、标识符、运算符、字符串扩展)
后端·python·学习·pycharm·学习方法·python3.11
我命由我123451 个月前
5.Python 数据容器(list 列表、tuple 元组、str 字符串、set 集合、dict(字典)、序列切片)
数据结构·windows·笔记·python·学习·list·python3.11
技术无疆2 个月前
【Python】Uvicorn:Python 异步 ASGI 服务器详解
运维·服务器·开发语言·网络·python·pygame·python3.11
技术无疆2 个月前
【Python】Arrow使用指南:轻松管理日期与时间
开发语言·人工智能·python·深度学习·机器学习·数据挖掘·python3.11