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
O5oz6z3
V2EX  ›  Python

一个小白想法, Python 为什么不通过命令行开关切换两种 GIL 模式?

  •  
  •   O5oz6z3 · 2021-10-23 22:04:15 +08:00 · 4090 次点击
    这是一个创建于 1105 天前的主题,其中的信息可能已经有所发展或是发生改变。
    最近 python 出现一个惊艳的 no-gil 设计,想必大家已经知道了。

    那么对于 python GIL 这个老问题,似乎常见的说法是:
    粗粒度的 GIL 降低多线程的性能,细粒度的 GIL 降低单线程的性能。

    那为什么不全都要,通过命令行开关切换两种 GIL 模式?
    我本身并不太懂同步原语、线程安全、并行编程这些,所以想请教一下。欢迎指正!
    27 条回复    2021-12-08 15:59:59 +08:00
    sujin190
        1
    sujin190  
       2021-10-23 23:24:50 +08:00   ❤️ 1
    设计复杂度啊,大哥,两个都要那就两个都性能底,还开关,想太多了,而且 Python 强大的 C 扩展,谁给你兼容,多线程编程本来就复杂,重新设计解释器干掉 gil 不是啥难事,但是要在通用场景下取得更好性能以及对现有模块和 C 扩展有良好兼容可就难了,而且以 Python 的主要使用场景来看,干不干掉 GIL 其实意义不大,反正 Python 做出的牛逼的东西像 tensorflow 都是 C 或者 C++扩展的本来就不受 GIL 限制,否则有 ironpython 和 jython 你看如何
    msg7086
        2
    msg7086  
       2021-10-24 05:48:21 +08:00   ❤️ 1
    成本。
    你来写吗?
    如果你不写,那可能别人也不想写,太多工程量了。
    而且你都用命令行开关切换了,那不就成运行时判断了吗?
    运行时判断会影响性能的,真要做的话还不如分开两套 binary 。

    当然上面说的 C 扩展本来就没有 GIL 也是因素之一。
    真要做 CPU 密集型操作不如写 C 扩展。
    O5oz6z3
        3
    O5oz6z3  
    OP
       2021-10-24 06:07:11 +08:00
    @sujin190 #1
    @msg7086 #2
    关于命令行开关,可能我说得不够清晰。我不了解 CPython ,以下举的例子可能不恰当:打个比方的话就是“单线程模式”用 `Py_Initialize()`,用普通的粗粒度 GIL 。“多线程模式”用 `Py_Initialize_threads_mode()`,采用细粒度的 GIL 优化多线程性能。

    更具体的话就是指 docs.python.org/zh-cn/3/faq/library.html#can-t-we-get-rid-of-the-global-interpreter-lock 文档里提到的那个细粒度 GIL 。既然能够实现细粒度 GIL ,那么在命令行启动解释器的时候选择用哪一种 GIL ,看上去应该很容易实现?

    至于那些已经存在的 C 扩展,虽然我也不太懂 C 扩展,但我猜如果本来就隐式或显式依赖 GIL ,那么似乎本来就不适合多线程并行?
    而且“多线程细粒度 GIL”是可选的,如果不兼容那么回退到原来的粗粒度 GIL 就是了。

    虽然我也不知道去掉 GIL 有什么意义,不过也许有利于并行计算?

    至于 python 其他没有 GIL 的实现,老实说我没用过,而且看上去版本更新缓慢……
    ysc3839
        4
    ysc3839  
       2021-10-24 06:11:10 +08:00
    那为什么不做成编译时的开关呢?
    O5oz6z3
        5
    O5oz6z3  
    OP
       2021-10-24 06:15:57 +08:00
    @msg7086 #2
    我的意思就是,如果暂时不考虑成本,这个方案理论上可行吗?
    况且细粒度 GIL 似乎(很久)以前有人实现过,参考上面 #3 的链接。

    至于你所说的“运行时判断”,如果我没理解错的话,是指每次解释执行字节码指令的时候,判断使用哪种 GIL ?我不是这个意思,我是指上面提到的根据命令行开关(例如`python --threads ...`)调用对应的“入口函数”(`Py_Initialize`/`Py_Initialize_threads`)。

    C 扩展这点也参考上面 #3 。虽然 CPU 密集确实应该用 C 扩展来解决,但 C 扩展的缺点是,需要编译(和需要写 C 语言……)。

    @ysc3839 #4
    python 的编译时开关?这个我不知道是什么……
    ysc3839
        6
    ysc3839  
       2021-10-24 06:21:06 +08:00
    @O5oz6z3 C 语言的预处理器。
    O5oz6z3
        7
    O5oz6z3  
    OP
       2021-10-24 06:33:08 +08:00
    @ysc3839 #6
    也就是和#2 楼说的一样,不用“命令行开关”,干脆用“编译时开关”,将 python 编译成细粒度 GIL 的可执行文件?
    感觉也可行,也就是开关的位置其实不太重要。
    那么问题就变成了:“Python 为什么不提供两种 GIL 对应的两套可执行文件?”
    msg7086
        8
    msg7086  
       2021-10-24 06:36:23 +08:00
    @O5oz6z3 不考虑成本,火星都能给你送人上去。
    你真不考虑成本,那都不用管 GIL 了,直接堆机房堆起来……还纠结什么性能问题,对吧。
    这个前提太没有意义了。

    而且就算不考虑成本,那也应该先去写 C 扩展。你看那么多年过去了,C 扩展的高性能库一大把,GIL 问题还没彻底解决,这是为什么?当然是因为写 C 扩展比较便宜简单啦……
    O5oz6z3
        9
    O5oz6z3  
    OP
       2021-10-24 07:44:30 +08:00
    @msg7086 #8
    理论可行性应该是成本的前提吧?理论不可行也就不需要考虑成本了……

    原来如此,看来多数情况下还是 c 扩展简单粗暴……

    看到一篇介绍 wiki.python.org/moin/GlobalInterpreterLock ,看来在目前的版本设计实现细粒度的 GIL 可能还是很有难度和很大工程量。(维护两套代码可能也很麻烦)
    joApioVVx4M4X6Rf
        10
    joApioVVx4M4X6Rf  
       2021-10-24 11:08:16 +08:00
    最近 python 出现一个惊艳的 no-gil 设计,想必大家已经知道了。
    村网通本村请问楼主是哪篇文章,想学习一下
    ErwinCheung
        11
    ErwinCheung  
       2021-10-24 11:11:09 +08:00
    最近 python 出现一个惊艳的 no-gil 设计,想必大家已经知道了。
    村网通本村请问楼主是哪篇文章,想学习一下
    zglzy
        12
    zglzy  
       2021-10-24 11:31:10 +08:00 via Android   ❤️ 1
    盲猜一下楼主指的是不是这个:
    aHR0cHM6Ly9kb2NzLmdvb2dsZS5jb20vZG9jdW1lbnQvdS8wL2QvMThDWGhEYjF5Z3hnLVlYTkJKTnpmelpzREZvc0I1ZTZCZm5YTGxlamQ5bDA=
    hsfzxjy
        13
    hsfzxjy  
       2021-10-24 12:14:46 +08:00 via Android   ❤️ 1
    我说一个观点,就是在 CPython 漫长的发展过程中 Extension 的接口会发生抽象泄漏,从而制约其底层实现的改变。具体可以看 Hyrum's Law https://www.hyrumslaw.com/

    展开来说,一个有很多用户使用的接口,无论其抽象做的多好,用户的使用最终多少会透过这层接口而去依赖背后的具体实现。CPython Extension API 虽然没有暴露太多和 GIL 相关的 API ,但你很难说不存在某些扩展,其正确性依赖于「解释器里有个全局锁」这一事实。就算细粒度锁或去除 GIL 的性能和安全问题解决了,CPython 作为正统及使用最广泛的版本也不会贸然采用。这其中会有很长的验证过程。
    kasheemlew
        14
    kasheemlew  
       2021-10-24 14:19:17 +08:00
    用 Cython 来操作也可,https://juejin.cn/post/7007043202251390984
    sujin190
        16
    sujin190  
       2021-10-24 15:21:00 +08:00
    @O5oz6z3 #3 大哥,这个又不是一个函数调完就完,各种数据结构,各种扩展都要加入支持,你用两个不同初始化方法有个啥用
    sujin190
        17
    sujin190  
       2021-10-24 15:23:38 +08:00
    @hsfzxjy #13 不是可能存在,是必然是这样啊,除非你做个扩展完全不用 python 解释器的任何数据结构,否则就必须要用 GIL 保证安全,但是你不用任何 Python 解释器的数据结构,那 Python 也认不了你的扩展啊
    2i2Re2PLMaDnghL
        18
    2i2Re2PLMaDnghL  
       2021-10-24 15:55:33 +08:00
    @hsfzxjy 其实可以做到避免抽象泄漏的,就是让实现本身不稳定
    比如 HTTP 接口,浏览器(几乎?)从未依赖于特定服务端实现
    wangyzj
        19
    wangyzj  
       2021-10-25 09:27:11 +08:00
    肯定可以实现
    就是没有那个必要了
    O5oz6z3
        20
    O5oz6z3  
    OP
       2021-10-25 09:43:22 +08:00
    @v2exblog @ErwinCheung #10 #11
    罚你们重看 /t/808955

    @kasheemlew #14
    我才发现我把 cython 和 c 扩展搞混了。

    @wangyzj #19
    我也不知道有没有必要,不过 GIL 好像有 CPU 颠簸之类的其他副作用……
    O5oz6z3
        21
    O5oz6z3  
    OP
       2021-10-25 09:46:08 +08:00
    @hsfzxjy #13
    感觉“抽象泄露”有点像是“依赖副作用”,不知道算不算是“隐式依赖 GIL”?
    看来 GIL 即使真的能去掉,距离正式使用也很漫长。

    @sujin190 #16
    因为我也不懂具体细节,所以还想着把 GIL 版本的初始化方法用的函数和数据结构复制修改成细粒度锁模式也许行得通。
    sujin190
        22
    sujin190  
       2021-10-25 11:06:36 +08:00   ❤️ 1
    @O5oz6z3 #21 问题就在于解析器你能复制数据结构再搞一遍,但是那么多模块和扩展怎么办,你说的这种不仅有人想过还有人搞过,但是有个啥用,各种模块扩展都不兼容,那这样的 python 还有个啥用,现在 python 重要使用的场景中数学计算、web 、人工智能、爬虫,几乎都不受 GIL 影响,语言自身性能不高主要也不是 GIL 导致的,从这些来说搞掉 GIL 并不是一个十分重要的事情,从 Python 编译成执行的字节码来看,对比 GO 、Rust 这种的编译器优化水平,似乎 python 的编译器还是有改进的空间的,以及 jit 支持之类的显然收益更高吧
    O5oz6z3
        23
    O5oz6z3  
    OP
       2021-10-25 16:02:06 +08:00
    @sujin190 #22
    明白了,比起对付 GIL ,还是先提升单线程的性能更划算。
    qdcanyun
        24
    qdcanyun  
       2021-10-26 18:56:51 +08:00   ❤️ 1
    其实是有可能有的,Python Core Developer Łukasz Langa 最近写的 [Blog]( https://lukasz.langa.pl/5d044f91-49c1-4170-aed1-62b6763e6ad0/) 中记录了 Python 核心开发团队和 nogil 的作者 Sam Gross 沟通的一些内容,其中就有提到
    > **Q: Is runtime enabling of nogil a long-term viable option or a transitional feature?**
    > Ideally the end game is CPython without the GIL, period. However, there will be an expected long period of community adaptation. We want to avoid a rift similar to the Python 2 to Python 3 transition. Rather, we want the transition to be easier, even if that means stretching it over a longer period of time.

    如果未来 nogil 能够 merge 进主干代码里,那么一开始势必会有一个 option 来让用户选择开关 GIL
    至于为什么现在没有,其实可以看 Sam Gross 的那个文档,以及上面提到的 Blog ,去掉 GIL 不是简单的直接删掉 GIL 对象,涉及到 GC ,内存分配,以及不少基础库的改造
    lolizeppelin
        25
    lolizeppelin  
       2021-10-31 20:15:16 +08:00 via iPhone
    async 这么多年了都没把全部库搞定
    gil 起码搞 10 年
    chinesehuazhou
        26
    chinesehuazhou  
       2021-11-21 09:22:35 +08:00 via Android   ❤️ 1
    楼上 @qdcanyun 提到了核心开发跟 nogil 作者的对话。未来估计会出现这么个开关。对话全文我翻译出来了,贴个链接: https://mp.weixin.qq.com/s/SvUyyUGLZFbqEyERWWJIYQ
    O5oz6z3
        27
    O5oz6z3  
    OP
       2021-12-08 15:59:59 +08:00
    才发现好像在以前,GIL 默认就是多线程时才会主动开启? docs.python.org/zh-cn/3/c-api/init.html#c.PyEval_InitThreads
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2472 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 10:31 · PVG 18:31 · LAX 03:31 · JFK 06:31
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.