Python支持多线程吗?它可以加快执行时间吗?

Kar*_*gat 83 python multithreading

关于多线程是否在Python中工作,我有点困惑.

我知道有很多关于这方面的问题,我已经读了很多,但我仍然感到困惑.我从自己的经验中了解到并且已经看到其他人在StackOverflow上发布他们自己的答案和示例,在Python中确实可以实现多线程.那么为什么每个人都一直说Python被GIL锁定并且一次只能运行一个线程呢?它显然确实有效.或者是否有一些区别我没有到这里?

许多海报/受访者也一直提到线程有限,因为它没有使用多个核心.但我会说它们仍然有用,因为它们可以同时工作,从而更快地完成组合工作量.我的意思是为什么甚至会有一个Python线程模块呢?

更新:

谢谢你到目前为止的所有答案.我理解的方式是多线程只能并行运行某些IO任务,但一次只能运行一个CPU绑定的多个核心任务.

我不完全确定这对我来说在实际意义上是什么意思,所以我只举一个我想要多线程的任务的例子.例如,假设我想遍历很长的字符串列表,我想对每个列表项执行一些基本的字符串操作.如果我拆分列表,将每个子列表发送给我的循环/字符串代码在新线程中处理,并将结果发送回队列,这些工作负载会大致同时运行吗?最重要的是,理论上这会加快运行脚本所需的时间吗?

另一个例子可能是如果我可以在四个不同的线程中使用PIL渲染和保存四个不同的图片,并且这比一个接一个地逐个处理图片更快?我想这个速度组件是我真正想知道的,而不是正确的术语.

我也知道多处理模块,但我现在主要关心的是中小型任务负载(10-30秒),所以我认为多线程会更合适,因为子进程可能很慢启动.

Mar*_*ers 112

GIL不会阻止线程化.所有GIL都确保一次只有一个线程正在执行Python代码; 控制仍然在线程之间切换.

GIL阻止的是利用多个CPU核心或单独的CPU并行运行线程.

这仅适用于Python代码.C扩展可以并且确实发布GIL以允许多个C代码线程和一个Python线程跨多个内核运行.这扩展到内核控制的I/O,例如select()调用套接字读取和写入,使Python在多线程多核设置中合理有效地处理网络事件.

然后,许多服务器部署运行多个Python进程,让操作系统处理进程之间的调度,以最大限度地利用CPU内核.如果适合您的用例,您还可以使用该multiprocessing来处理来自一个代码库和父进程的多个进程的并行处理.

请注意,GIL仅适用于CPython实现; Jython和IronPython使用不同的线程实现(分别是本机Java VM和.NET公共运行时线程).

直接解决您的更新:任何尝试使用纯Python代码从并行执行中获得速度提升的任务都不会加速,因为线程Python代码被锁定到一次执行的一个线程.但是,如果混合使用C扩展和I/O(例如PIL或numpy操作),并且任何C代码都可以与一个活动的Python线程并行运行.

Python线程非常适合创建响应式GUI,或者用于处理多个短Web请求,其中I/O是比Python代码更多的瓶颈.它不适合并行化计算密集型Python代码,坚持使用multiprocessing模块执行此类任务或委托给专用外部库.

  • 不,我认为这样的答案不会很有帮助; 老实说.你无法创建一个详尽的列表,但经验法则是任何I/O(文件读写,网络套接字,管道)都是用C语言处理的,而且很多C库也为它们发布了GIL操作,但由图书馆为您记录. (4认同)
  • 虽然它与这个问题没有直接关系,但值得注意的是,有时线程与性能无关; 将代码编写为多个独立的执行线程可能更简单.例如,您可能有一个线程播放背景音乐,一个用于UI,另一个用于计算,最终必须完成,但不会匆忙.尝试使用UI runloop对下一个音频缓冲区进行排序,或者将计算分解成足够小的部分以不干扰交互性,可能比使用线程要困难得多. (3认同)
  • 我的不好,直到现在才看到您更新的答案,您在其中提供了一些线程使用的很好的示例。其中包括 **(如果我错了,请纠正我)** 网络编程(例如 `urllib.urlopen()`?),从 Python GUI 中调用一个 Python 脚本,以及调用多个 PIL(例如 `Image.transform()) `) 和 numpy(例如 `numpy.array()`)与线程的操作。您在评论中提供了更多示例,例如使用多线程读取文件(例如“f.read()”?)。我知道不可能提供详尽的列表,只是想要您在更新中提供的示例类型。不管怎样,接受你的答案:) (2认同)
  • @KarimBahgat:是的,`urllib.urlopen()`会调用网络套接字,等待套接字I/O是切换线程和执行其他操作的绝佳机会. (2认同)

zor*_*ord 6

是的。:)

您有低级线程模块和高级线程模块。但是如果你只是想使用多核机器,多处理模块是要走的路。

来自文档的引用:

在 CPython 中,由于全局解释器锁,一次只有一个线程可以执行 Python 代码(即使某些面向性能的库可能会克服这一限制)。如果您希望您的应用程序更好地利用多核机器的计算资源,建议您使用多处理。但是,如果您想同时运行多个 I/O 密集型任务,线程仍然是一个合适的模型。


小智 5

Python 中允许线程,唯一的问题是 GIL 将确保一次只执行一个线程(无并行性)。

因此,基本上,如果您想要多线程代码来加速计算,它不会加速计算,因为一次只执行一个线程,但如果您使用它与数据库交互,例如它会加速。