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

Python支持多线程吗?它能加快执行时间吗?,python,multithreading,Python,Multithreading,我对多线程是否在Python中工作有点困惑 我知道有很多关于这方面的问题,我读过很多,但我仍然感到困惑。根据我自己的经验,我知道并且看到其他人在StackOverflow上发布了他们自己的答案和示例,在Python中多线程确实是可能的。那么,为什么每个人都说Python被GIL锁定,一次只能运行一个线程?它显然起作用了。还是有什么区别我不明白 许多海报/受访者还不断提到线程是有限的,因为它不使用多核。但我想说,它们仍然很有用,因为它们同时工作,因此可以更快地完成合并的工作负载。我的意思是,为什么

我对多线程是否在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在多线程多核设置中合理有效地处理网络事件

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

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

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

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

是。)

您有低级模块和高级模块。但如果你只是想使用多核机器,那么模块就是一条出路

引自:

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


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


因此,基本上,如果您希望多线程处理代码以加快计算速度,它不会加快计算速度,因为一次只执行一个线程,但是如果您使用它与数据库交互,例如,它会加快计算速度

我喜欢海报,因为答案总是“这取决于你想做什么”。然而,根据我的经验,python中的并行加速一直都很糟糕,即使对于多处理也是如此

例如,查看本教程(谷歌排名第二):

我对这段代码进行了计时,并增加了池映射函数的进程数(2,4,8,16),得到了以下错误计时:

serial 70.8921644706279 
parallel 93.49704207479954 tasks 2
parallel 56.02441442012787 tasks 4
parallel 51.026168536394835 tasks 8
parallel 39.18044807203114 tasks 16
代码: #在开始时增加数组大小 #我的计算节点有40个CPU,所以这里有足够的空闲空间

arr = np.random.randint(0, 10, size=[2000000, 600])
.... more code ....
tasks = [2,4,8,16]

for task in tasks:
    tic = time.perf_counter()
    pool = mp.Pool(task)

    results = pool.map(howmany_within_range_rowonly, [row for row in data])

    pool.close()
    toc = time.perf_counter()
    time1 = toc - tic
    print(f"parallel {time1} tasks {task}")

这是一个相当复杂的问题。我认为答案在于你想让线程做什么。在大多数情况下,GIL会阻止多个线程同时运行。然而,在一些情况下,GIL是发布的(例如,从文件中读取),因此可以在第