我对多线程是否可以在Python中工作感到有些困惑。
我知道对此有很多疑问,我已经阅读了很多,但是我仍然很困惑。我从自己的经验中知道,并且看到其他人在StackOverflow上发表了自己的答案和示例,说在Python中确实可以实现多线程。那么为什么每个人都说Python被GIL锁定并且一次只能运行一个线程呢?显然可以。还是我不来这里有什么区别?
许多张贴者/受访者还不断提到线程是有限的,因为它不使用多个核心。但是我会说它们仍然有用,因为它们可以同时工作,因此可以更快地完成合并的工作量。我的意思是为什么还要有Python线程模块呢?
更新:
到目前为止,感谢您提供所有答案。据我了解,多线程只能并行运行某些IO任务,而一次只能运行一个CPU绑定的多个核心任务。
我并不完全确定这对我实际上意味着什么,所以我仅举一个我想进行多线程的任务示例。例如,假设我要遍历很长的字符串列表,并且希望对每个列表项执行一些基本的字符串操作。如果我拆分列表,将每个要由我的循环/字符串代码处理的子列表发送到新线程中,然后将结果发送回队列中,这些工作负载是否会大致同时运行?最重要的是,从理论上讲,这会加快运行脚本的时间吗?
另一个例子可能是,如果我可以在四个不同的线程中使用PIL渲染和保存四张不同的图片,并且这比一张又一张地处理图片要快吗?我想这个速度要素是我真正想知道的,而不是正确的术语。
我也了解多处理模块,但是我现在的主要兴趣是中小型任务负载(10-30秒),因此我认为多线程将更合适,因为子进程的启动速度很慢。
GIL不会阻止线程化。GIL所做的全部工作就是确保一次只有一个线程在执行Python代码。控制仍然在线程之间切换。
GIL当时阻止的事情是利用多个CPU内核或单独的CPU并行运行线程。
这仅适用于Python代码。C扩展可以并且确实会发布GIL,以允许C代码的多个线程和一个Python线程跨多个内核运行。这扩展到由内核控制的I / O,例如select()对套接字读写的调用,使Python在多线程多核设置中合理有效地处理网络事件。
select()
然后,许多服务器部署将运行多个Python进程,以使OS处理进程之间的调度,以最大程度地利用CPU内核。如果适合您的用例,您还可以使用该multiprocessing库来处理来自一个代码库和父进程的多个进程的并行处理。
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此类任务的模块或委托给专用的外部库。