【问题标题】:How efficient is threading in Python?Python中的线程效率如何?
【发布时间】:2011-07-04 22:12:55
【问题描述】:

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

这是真的吗?如果是这样,Python 程序员如何克服这个问题?

【问题讨论】:

  • 请注意,GIL 仅存在于 CPython 中。你仍然可以使用 IronPython 之类的东西,并且不会因使用线程而受到(同样多的)惩罚。
  • 其实听说效率挺高的。
  • 有人可以发布一些指向python中多线程问题/或非问题的链接吗?
  • 关于线程和python的问题已经很多了......

标签: python multithreading


【解决方案1】:

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

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

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

【讨论】:

  • 或者甚至比单线程程序的性能更差:请参阅 Dave Beazley 的这篇精彩演讲,Understanding the GIL 以深入了解。
【解决方案2】:

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

在单核机器上,这无关紧要 - 无论如何,所有线程都是通过时间片伪造的。在多核机器上,情况有所不同:在 CPython 上运行的受 CPU 限制的 Python 程序不会使用所有可用的内核。

对此有多种可能的回应:

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

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

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:

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

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

      【讨论】:

        【解决方案5】:

        线程在 CPython 中是高效的,但线程不能在不同的处理器/内核上同时运行。大概就是这个意思。仅当您需要进行共享内存并发时,它才会影响您。

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

        【讨论】:

          【解决方案6】:

          找到解决方案后(下)不知道为什么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 
          

          【讨论】:

          • 因为Thread 类和Pool 类是两个不同的东西。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-05-24
          • 1970-01-01
          • 2021-09-21
          • 1970-01-01
          • 2015-03-26
          • 2011-08-04
          • 2018-09-02
          相关资源
          最近更新 更多