Python中的线程效率如何?

时间:2011-02-26 16:19:11

标签: python multithreading

我听说Python中的线程效率不高(与其他语言相比)。

这是真的吗?如果是这样,Python程序员怎么能克服这个呢?

6 个答案:

答案 0 :(得分:19)

人们之所以说多线程在python中效率不高是因为Global Interpreter Lock。由于编写解释器的方式,只有一个线程可以同时安全地在解释器中执行代码。

这意味着如果你的线程有很大的计算限制,也就是说,在解释器中做了很多东西,那么你实际上仍然只具有单线程程序的性能。在这种情况下,您可能最好使用多处理模块,该模块与多线程模块具有相同的接口,但会启动解释器的多个副本(这样做的缺点是您必须明确共享内存)。

如果你正在做一些严重IO绑定的事情,你仍然可以在python中从多线程中获得速度提升。当一个线程正在等待磁盘或网络i / o时,其他线程仍然可以执行,因为当线程阻塞时它们会释放解释器锁。

答案 1 :(得分:9)

CPython将引用计数与循环垃圾收集器一起用于内存管理。为了实现这一点,它有一个称为“全局解释器锁”的机制,它保护引用计数系统以及所有其他解释器内部。

在单核机器上,这没关系 - 无论如何,所有线程都是通过时间切片伪造的。在多核机器上,它有所不同:在CPython上运行的CPU绑定Python程序将不会使用所有可用内核。

对此有很多可能的回应:

  • 使用多个进程而不是多个线程(也为多台机器开辟了未来的可扩展性,而不是单个机器中的不同内核)
  • 使用具有更多核友好垃圾收集机制的Python实现(例如Jython,IronPython或PyPy)
  • 将更密集的CPU操作移出C代码并在进行计算时释放GIL(因此允许C代码在其他内核上运行,即使任何时候只有一个Python线程处于活动状态)

如果使用线程将阻塞IO转换为非阻塞操作,那么在标准CPython中可以正常工作而无需任何特殊修改 - IO操作已经释放了GIL。

答案 2 :(得分:5)

您可以使用multiprocessing来克服此问题!它就像python中的多线程一样简单,但却为你提供了所有cpu内核的全部功能。

  

multiprocessing是一个使用类似于线程模块的API支持产生进程的包。多处理包提供本地和远程并发,通过使用子进程而不是线程有效地侧向执行全局解释器锁。因此,多处理模块允许程序员充分利用给定机器上的多个处理器。它可以在Unix和Windows上运行。

答案 3 :(得分:1)

一种选择是使用不同的Python实现,如Jython或IronPython。这样,您仍然可以获得使用Python语言而不必处理GIL的好处。但是,您将无法使用仅限CPython的库。

另一种选择是使用与线程不同的构造。例如,如果您使用Stackless Python,Tasklets是另一种选择。

答案 4 :(得分:1)

线程在CPython中很有效,但线程无法在不同的处理器/内核上并发运行。这可能就是这个意思。如果您需要执行共享内存并发,它只会影响您。

其他Python实现没有这个问题。

答案 5 :(得分:0)

找到解决方案后(下面)我想知道为什么python仍然有线程类

from multiprocessing import Pool

def some_function(x):
    return x*x

Xs = [i for i in xrange(1, 1000)]      # make 1, 2, ..., 999, 1000

pool = Pool(processes=16)              # start 16 worker processes on 16 CPU
print pool.map(some_function, Xs)      # print out