Python 不能利用多核的问题以后能被解决吗?
程序员文章站
2022-04-13 11:50:09
...
今天看了一篇文章Python 最难的问题,说到Python受限于GIL。不要使用多线程,请使用多进程。
问:
假设去掉GIL,像Java那样的多核多线程,你会面临更多头疼的OOM问题,以及GC问题,Java的一次Full GC是stop whole world的,你不希望你整个服务器8颗内核一起stop,等待GC完成吧?
所以Java这么多年疯狂投入努力改进VM的GC效率,搞出来各种GC算法,特别是并行GC算法。而且在大内存服务器上,为了提高GC效率,避免过大的内存堆扫描开销,Java现在也强调单机跑多进程呢。
所以你认为Python/Ruby去掉GIL,就解决问题了吗?事实上会引入更多更麻烦的问题。
如果为了提高IO并发性能,用协程就同样可以达到目的,Ruby现在原生支持协程,Lua则是协程方面效率极高的脚本语言,已经证明了这条路。
最后说到多核的问题,Ruby未来发展方向是MVM,即单进程里面跑多个VM,每个CPU内核跑一个VM,每个VM有自己的GC。这个办法其实很不错,既有效利用了进程共享内存,又可以支持多核并行,还解决了全局GC的性能问题。
关于Python最大的误区大概就是“Python的多线程不能利用多核”会传来传去以后变成“Python不能利用多核”。
以现在Python主流应用之一服务器开发举例,根据CPU核心开对应数量的进程是非常普遍的做法。
至于非要用“多线程”的场合(比如异步),也有不少“协程”方案可以使用,比如stackless python,又比如greenlet,以及由此发展出的可爱的gevent。 首先,语言应该在什么级别支持多线程。C 通过操作系统的 preemptive scheduler 支持多线程,同时提供 critical section, wait/notify 这样的同步机制。问题在于,这样的同步机制太低级,在实际应用中经常需要封装为高级的同步机制,比如多线程的生产者-消费者队列。高级动态语言的设计者面临三个选择:
移除 GIL 难吗?不难,因为根本没有必要移除。如果 Python 能在一个进程中初始化多个 VM,同时其标准库在 C 级别做出足够多的常用多核优化就没有问题。Python 其实是希望实现另一个功能,异步操作。尽管异步操作和并行计算都可以通过多线程来完成,但是其实前者更加适合用协程或者用户级线程来完成。但是 Python 是 stackful 实现,也就是 byte code 借用 C runtime stack 来维护自己的运行状态。这种机制的弱点就是不容易用跨平台的方式来实现协程,所以利用 OS 多线程加 GIL 也就成了模拟协程语意的妥协手段。
补充一下。C 的线程和线程同步机制虽然底层,但是只有这种机制才能覆盖所有 use case。而其它的高层抽象只能适合某种 case。所以,当我说高级动态语言需要高级的线程操作时,我的隐含意思是这种语言同时还要有和 C 进行良好的互操作来随时扩展这种抽象。
如果有多核,那应该是要追求大并发,高吞吐量。
这时候python还是洗洗睡吧。
当然这个世界上总是有些很奇葩的技术。
例如用C#写的操作系统。
SharpOS (operating system)
一个技术费了很大功夫去实现了别的技术轻而易举就可以完成的事情。
不是一件值得高兴和称赞的事情。
工具是用来解决问题的,不是制造问题。 1,暂没有计划,主要是对现有GC的有影响很大,有实现难度。
2,同Rio的答案,不过其他语言不了解了。
3,
GIL的影响没想象的那么大,比如对于io密集型(网络/磁盘)程序。
pypy之前提供了一个去掉GIL的思路(基于STM):
http://morepypy.blogspot.jp/2011/06/global-interpreter-lock-or-how-to-kill.html
但是在pypy2.0版本中还是没有做到去掉GIL。
除了多进程之外,采用协程(stackless python)也是一个不错的解决思路,不过我也没有做过性能测试。 。。。。谁告诉你不能利用了 CPython不能直接支持多线程的理由全是bullshit,Java/C#从第一版就支持,因为这本来就是理所应当的 这是一个好问题。由于GIL的限制cPython无法简单充分利用多核处理器的并行处理能力,而使用multiprocessing之类的多进程方式,在进程间通信上会耗费额外多的开销,也达不到多线程应有的效率。
另一方面看来,目前python在大数据量高并发度方面的瓶颈并不是很明显,python通常用于处理轻量级的任务。在我工作中使用python处理上T级别的自然语料库的时候,也是依托于mapreduce平台,所以大数据处理中不能多线程实际上也并不是一个很明显的问题。
而且彻底修改现在的GIL机制牵扯到从底层重新设置cPython的核心,包括资源同步、gc策略等等,如果真的这样修改,会大大降低python处理简单单线程任务的性能,因为即使是单线程也需要做资源同步的话,开销是相当大的。所以cPython在可预见的未来都不会改掉现在的GIL。
问:
- Python多核利用的问题,在以后会解决吗?
- 其他解释型语言,如Ruby是不是也存在同样的问题?
- 目前的解决方案是什么?
回复内容:
Ruby也有GIL,其实GIL并不是性能问题的根源,性能问题的根源是GC。假设去掉GIL,像Java那样的多核多线程,你会面临更多头疼的OOM问题,以及GC问题,Java的一次Full GC是stop whole world的,你不希望你整个服务器8颗内核一起stop,等待GC完成吧?
所以Java这么多年疯狂投入努力改进VM的GC效率,搞出来各种GC算法,特别是并行GC算法。而且在大内存服务器上,为了提高GC效率,避免过大的内存堆扫描开销,Java现在也强调单机跑多进程呢。
所以你认为Python/Ruby去掉GIL,就解决问题了吗?事实上会引入更多更麻烦的问题。
如果为了提高IO并发性能,用协程就同样可以达到目的,Ruby现在原生支持协程,Lua则是协程方面效率极高的脚本语言,已经证明了这条路。
最后说到多核的问题,Ruby未来发展方向是MVM,即单进程里面跑多个VM,每个CPU内核跑一个VM,每个VM有自己的GC。这个办法其实很不错,既有效利用了进程共享内存,又可以支持多核并行,还解决了全局GC的性能问题。
- 在可以遇见的相当长一段时间内,Python 的官方实现 CPython 不会解决 GIL 的问题。
- Ruby 的官方实现 MRI 也有这个问题。
- 解决方案有很多,最常见的当然是用多进程。如果条件允许,也可以选择没有 GIL 限制的实现,比如基于 JVM 的 Jython 和 JRuby。
关于Python最大的误区大概就是“Python的多线程不能利用多核”会传来传去以后变成“Python不能利用多核”。
以现在Python主流应用之一服务器开发举例,根据CPU核心开对应数量的进程是非常普遍的做法。
至于非要用“多线程”的场合(比如异步),也有不少“协程”方案可以使用,比如stackless python,又比如greenlet,以及由此发展出的可爱的gevent。 首先,语言应该在什么级别支持多线程。C 通过操作系统的 preemptive scheduler 支持多线程,同时提供 critical section, wait/notify 这样的同步机制。问题在于,这样的同步机制太低级,在实际应用中经常需要封装为高级的同步机制,比如多线程的生产者-消费者队列。高级动态语言的设计者面临三个选择:
- 在语言中直接提供类似 C 的机制(Java);
- 设计良好的 C 接口,在同一进程中运行多个虚拟机,利用 C 把低级同步机制封装成多虚拟机之间的高级同步机制(Lua),或者把多线程优化完全封装在一个 API 之内(比如 Intel MKL 的各种多核算法)。
- 多进程。
移除 GIL 难吗?不难,因为根本没有必要移除。如果 Python 能在一个进程中初始化多个 VM,同时其标准库在 C 级别做出足够多的常用多核优化就没有问题。Python 其实是希望实现另一个功能,异步操作。尽管异步操作和并行计算都可以通过多线程来完成,但是其实前者更加适合用协程或者用户级线程来完成。但是 Python 是 stackful 实现,也就是 byte code 借用 C runtime stack 来维护自己的运行状态。这种机制的弱点就是不容易用跨平台的方式来实现协程,所以利用 OS 多线程加 GIL 也就成了模拟协程语意的妥协手段。
补充一下。C 的线程和线程同步机制虽然底层,但是只有这种机制才能覆盖所有 use case。而其它的高层抽象只能适合某种 case。所以,当我说高级动态语言需要高级的线程操作时,我的隐含意思是这种语言同时还要有和 C 进行良好的互操作来随时扩展这种抽象。
推荐阅读
道可叨 | python 线程,GIL 和 ctypes
这篇文章从:
1.python 不必要去除GIL, 去除GIL了运行效率会降低
2.使用多进程并行代码
3.使用ctypes绕开GIL实行多线程并行
解释了GIL
同意梁智的答案。如果有多核,那应该是要追求大并发,高吞吐量。
这时候python还是洗洗睡吧。
当然这个世界上总是有些很奇葩的技术。
例如用C#写的操作系统。
SharpOS (operating system)
一个技术费了很大功夫去实现了别的技术轻而易举就可以完成的事情。
不是一件值得高兴和称赞的事情。
工具是用来解决问题的,不是制造问题。 1,暂没有计划,主要是对现有GC的有影响很大,有实现难度。
2,同Rio的答案,不过其他语言不了解了。
3,
GIL的影响没想象的那么大,比如对于io密集型(网络/磁盘)程序。
pypy之前提供了一个去掉GIL的思路(基于STM):
http://morepypy.blogspot.jp/2011/06/global-interpreter-lock-or-how-to-kill.html
但是在pypy2.0版本中还是没有做到去掉GIL。
除了多进程之外,采用协程(stackless python)也是一个不错的解决思路,不过我也没有做过性能测试。 。。。。谁告诉你不能利用了 CPython不能直接支持多线程的理由全是bullshit,Java/C#从第一版就支持,因为这本来就是理所应当的 这是一个好问题。由于GIL的限制cPython无法简单充分利用多核处理器的并行处理能力,而使用multiprocessing之类的多进程方式,在进程间通信上会耗费额外多的开销,也达不到多线程应有的效率。
另一方面看来,目前python在大数据量高并发度方面的瓶颈并不是很明显,python通常用于处理轻量级的任务。在我工作中使用python处理上T级别的自然语料库的时候,也是依托于mapreduce平台,所以大数据处理中不能多线程实际上也并不是一个很明显的问题。
而且彻底修改现在的GIL机制牵扯到从底层重新设置cPython的核心,包括资源同步、gc策略等等,如果真的这样修改,会大大降低python处理简单单线程任务的性能,因为即使是单线程也需要做资源同步的话,开销是相当大的。所以cPython在可预见的未来都不会改掉现在的GIL。