Python全局解释器锁(GIL)解决方案在Linux上使用taskset的多核系统?

Kur*_*urt 21 python multithreading multicore gil python-stackless

所以我刚刚在Python全局解释器锁(GIL)http://blip.tv/file/2232410上看完了这个演讲.

它的要点是GIL对于单核系统来说是一个非常好的设计(Python实际上将线程处理/调度留给了操作系统).但是,这可能严重地适应多核系统,最终导致IO密集型线程被CPU密集型线程严重阻塞,上下文切换费用,ctrl-C问题[*]等等.

因此,由于GIL限制我们基本上在一个CPU上执行Python程序,我的想法是为什么不接受这个并简单地在Linux上使用taskset来设置程序与系统上某个核心/ cpu的亲和性(特别是在某种情况下)在多核系统上运行的多个Python应用程序)?

所以最终我的问题是:有没有人尝试在Linux上使用带有Python应用程序的任务集(特别是在Linux系统上运行多个应用程序,以便多个核心可以与一个或两个绑定到特定核心的Python应用程序一起使用),如果是这样的话是结果?值得做吗?是否会使某些工作负载更糟糕?我打算这样做并进行测试(基本上看看程序是否需要花费更多或更少的时间来运行),但我很乐意听取其他人的经验.

另外:David Beazley(在链接视频中发表演讲的人)指出,一些C/C++扩展手动释放GIL锁,如果这些扩展针对多核进行优化(即科学或数字数据分析/等),那么而不是为数字运算获得多核的好处,扩展将被有效地削弱,因为它仅限于单个核心(因此可能显着降低程序速度).另一方面,如果您没有使用此类扩展

我没有使用多处理模块的原因是(在这种情况下)程序的一部分是严重的网络I/O绑定(HTTP请求),所以有一个工作线程池是一个很好的方式从一个盒子挤出性能一个线程触发一个HTTP请求,然后因为它在I/O上等待就放弃了GIL而另一个线程可以做到这一点,所以程序的一部分可以轻松地运行100多个线程而不会伤害CPU太多让我实际使用可用的网络带宽.对于无堆栈的Python/etc,我对重写程序或替换我的Python堆栈并不过分感兴趣(可用性也是一个问题).

[*]只有主线程可以接收信号,所以如果你发送一个ctrl-C,Python解释器基本上试图让主线程运行,这样它就可以处理信号,但因为它不能直接控制运行哪个线程(它留给操作系统)它基本上告诉操作系统继续切换线程,直到它最终命中主线程(如果你不幸,可能需要一段时间).

yni*_*ous 9

另一个解决方案是:http: //docs.python.org/library/multiprocessing.html

注1:这不是 Python语言的限制,而是CPython实现的限制.

注意2:关于亲和力,您的操作系统本身应该没有问题.

  • 如果您使用线程进行IO,GIL不应该(通常)成为问题.Python IO例程通常用C语言编写,并在运行期间释放GIL.当多个线程需要在解释器上运行python字节码时,会遇到GIL的大问题. (4认同)
  • Morover,如果您正在编写网络应用程序,我建议您查看http://twistedmatrix.com/.通过学习曲线后,它将使您的生活更轻松. (2认同)
  • 有没有理由不能将miltiprocessing模块用于CPU绑定线程? (2认同)

Van*_*ale 6

我从未听说有人使用taskset来提高Python的性能.并不意味着它不会发生在您的情况下,但绝对发布您的结果,以便其他人可以批评您的基准测试方法并提供验证.

就个人而言,我会使用消息队列将您的I/O线程与CPU绑定线程分离.这样你的前端现在完全是网络I/O绑定(一些带有HTTP接口,一些带有消息队列接口),非常适合你的线程情况.然后,CPU密集型进程可以使用多处理,也可以只是等待工作到达消息队列的单个进程.

从长远来看,您可能还需要考虑使用Twisted或类似eventlets来替换线程I/O前端,因为即使它们无法帮助提高性能,它们也应该提高可伸缩性.您的后端现在已经可以扩展,因为您可以根据需要在任意数量的计算机上运行消息队列+ cpu.


wr.*_*wr. 1

多年来,我发现以下经验法则足够了:如果工作线程依赖于某种共享状态,我会为每个核心使用一个多处理进程(CPU 限制),并为每个核心使用一个固定工作线程池(I/O 限制) )。操作系统将负责将不同的 Python 进程分配给内核。

  • 我这样做了,我的建议是使用多处理将 CPU 负载分配给处理器(假设这些进程之间不需要共享太多信息),并使用线程来满足 I/O 需求。 (2认同)