V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
jenrey
V2EX  ›  Python

Python GIL 的问题

  •  
  •   jenrey · 2023-09-03 23:04:54 +08:00 · 2244 次点击
    这是一个创建于 476 天前的主题,其中的信息可能已经有所发展或是发生改变。

    如下图所示,Python 使用 GIL 也会出现图中这样的问题,那么 GIL 存在的意义是什么?谢谢 https://imgur.com/a/YCoqzm1

    16 条回复    2023-09-27 11:35:42 +08:00
    liprais
        1
    liprais  
       2023-09-03 23:05:52 +08:00
    你的意思是单核 cpu 就不能有多线程了?
    iseki
        2
    iseki  
       2023-09-03 23:07:39 +08:00
    原始链接呢,原文呢,按理说不该有这样的问题
    jenrey
        3
    jenrey  
    OP
       2023-09-03 23:26:48 +08:00
    @liprais 我感觉图中的意思,只是想表达 Python GIL 在单核 CPU 下进行多线程并发,仍需要给 obj 对象加锁。
    而 Python GIL 的诞生 只是为了解决 在多核 CPU 下执行多线程“并行”任务时 Python 的引用计数器不是线程安全 的问题。也就是说 Python GIL 的出现让多核 CPU 下执行多线程 并发 任务时引用计数器是线程安全的。
    所以,这个图配得不好,应该加个标题《即使有 Python GIL ,我们仍需给共享对象加锁,无论 CPU 核心数》。
    不知道我理解的对不对。
    wevsty
        4
    wevsty  
       2023-09-03 23:47:13 +08:00
    单核时代一样可以多进程,多线程。
    线程的调度是由 OS 来决定的,跟你有几个 CPU 核心没有必然的关系。
    lovelylain
        5
    lovelylain  
       2023-09-04 00:11:34 +08:00 via Android
    @jenrey 写过多线程程序没?多线程环境下操作同一个对象,为了避免线程安全问题,最常见的方案就是加锁,Python GIL 同理,如果编译为不支持多线程,是不需要 GIL 的,但支持多线程后,为了避免引用技等出现
    lovelylain
        6
    lovelylain  
       2023-09-04 00:14:49 +08:00 via Android
    @jenrey 写过多线程程序没?多线程环境下操作同一个对象,为了避免线程安全问题,最常见的方案就是加锁,Python GIL 同理,如果编译为不支持多线程,是不需要 GIL 的,但支持多线程后,为了避免引用计数等出现线程安全问题,就引入了 GIL ,单核 CPU 也可以多线程
    也存在线程安全问题的。
    jackOff
        7
    jackOff  
       2023-09-04 01:48:25 +08:00 via Android
    Python 全局解释器导致了多线程大多数情况就是个笑话,仅仅在网络通信和读写文件上能稍微体现一点。其他方面使用它还不如使用异步编程,当然多进程可以改善这种情况,但是这就是使代码开发变得极度简单化的一个代价
    mylifcc
        8
    mylifcc  
       2023-09-04 02:02:11 +08:00
    GIL 是解释器级别的锁,可以保证同一时间只有 1 个线程在 CPU 运行来改这个参数,如果用 GO 就可能会有多个线程在同时改了,这样说你懂了吧。。。这个问题属于业务级别的问题,归根结底是设计问题,你允不允许非同一时间的线程来改一个值的,如果允许,就不需要加锁,因为你业务就是这么设计的。
    ysc3839
        9
    ysc3839  
       2023-09-04 02:59:59 +08:00 via Android
    不会出现图中的问题,加锁之后需要持有锁的线程主动解锁,此时如果切换到了线程 B ,线程 B 没法锁定,就只能等待。
    est
        10
    est  
       2023-09-04 09:07:18 +08:00
    你说下这图谁画的吧。我让作者出来给你解释。
    itskingname
        11
    itskingname  
       2023-09-04 09:55:46 +08:00
    我以前写过一篇文章来说明这个问题: https://mp.weixin.qq.com/s/a37OxUjgHdps1ZsPB7pKcQ
    sujin190
        12
    sujin190  
       2023-09-04 10:35:31 +08:00   ❤️ 1
    GIL 限制的是单个字节码级别的原子操作不能并发,就算是简单 a+=1 这样的也是需要多条字节码指令的,所以也不能保证是原子操作,并不是你想的那种给对象加锁,你可以用 dis 模块研究下代码和编译生成的字节码对应关系
    jenrey
        13
    jenrey  
    OP
       2023-09-04 13:19:30 +08:00
    @ysc3839 所以我感觉原图和 GIL 锁的原理没啥关系,只是表明 Python 有了 GIL 后,在多线程下是并发执行的,而非并行执行,与 CPU 的核心数也无关系,只会采用单核心时间片调度多个线程,所以只是个提醒图(提醒如果不给共享对象加锁,会出问题而已)
    引用计数器的方案有瑕疵,即 当两个线程同时提高同一个对象的引用计数时,(如果没有 GIL 锁)那么引用计数只会被提高了 1 次而不是 2 次。所以 GIL 就诞生了。
    NoAnyLove
        14
    NoAnyLove  
       2023-09-04 16:20:36 +08:00
    不会出现这种问题,GIL 会保证每条指令的执行是 atomic 的,可以看看 https://www.v2ex.com/t/965954

    如果主动撤销对某个 obj 的引用,多半是是使用`del obj`语句(也可能是其他语句),也就是一条 DELETE_NAME (或者别的 DELETE 指令)。减少引用和具体的回收工作都在这一条指令中完成了,

    ```
    >>> import dis
    >>> dis.dis("del obj")
    1 0 DELETE_NAME 0 (obj)
    2 LOAD_CONST 0 (None)
    4 RETURN_VALUE
    ```
    akaHenry
        15
    akaHenry  
       2023-09-06 10:28:46 +08:00
    GIL 不防呆.
    Cu635
        16
    Cu635  
       2023-09-27 11:35:42 +08:00
    链接里面的图是用什么画的?
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1255 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 17:34 · PVG 01:34 · LAX 09:34 · JFK 12:34
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.