使用 python 多处理池时睡眠作业占用核心

Sleeping jobs occupying cores when using python multiprocessing pool

我在 python 中使用 multiprocessing.Pool 来安排大约 2500 个作业。我正在提交这样的工作:

pool = multiprocessing.Pool()
for i from 1 to 2500: # pseudocode
    jobs.append(pool.apply_async(....))
for j in jobs:
    _ = job.get()

作业是这样的,经过一些计算后,它们会休眠很长时间,等待某个事件完成。我的期望是,当他们睡觉时,其他等待的工作会得到安排。但事实并非如此。单次调度的最大作业数在23左右(即使它们都在休眠,ps aux显示状态S+)这是机器中或多或少的核心数。只有在一个作业完成并释放核心后,才会安排另一个作业。

我的期望是一次安排所有 2500 个作业。如何让 python 一次提交所有 2500 个职位?

pool = multiprocessing.Pool() 将使用所有可用的内核。如果您需要使用特定数量的进程,您需要将其指定为参数。

pool = multiprocessing.Pool(processes=100)

Python 的多处理和线程包使用 process/thread 池。默认情况下,池中 processes/threads 的数量取决于硬件并发性(即通常是处理器支持的 硬件线程数 )。您可以调整这个数字,但您真的不应该创建太多线程或进程,因为它们是操作系统 (OS) 的 宝贵资源 。请注意,对于大多数 OS,线程比进程更便宜,但 CPython 使线程不是很有用(IO latency-bound 作业除外),因为 全局解释器锁(吉尔)。创建 2500 processes/threads 会给 OS 调度程序带来很大压力,并且整个系统会变慢。 OS 是这样设计的,等待线程并不昂贵,但频繁唤醒显然会很昂贵。此外,在给定平台上可以创建的 processes/threads 数量是有限的。 AFAIR,在我的旧 Windows 7 系统上,这被限制为 1024。最大的问题是每个线程需要一个通常初始化为 1~2 MiB 的堆栈,因此创建 2500 个线程将占用 2.5~5.0 GiB 的 RAM!这对于流程来说将是最糟糕的。更不用说缓存未命中会更频繁,从而导致执行速度变慢。因此,简而言之,不要创建 2500 个线程或进程:这太昂贵了

您不需要线程或进程,您需要 fibers or more generally green threads likes greenlet or eventlet as well as gevent coroutines。最后一个以速度快着称,支持 thread-pools。或者,您可以使用 Python 的最新 async 功能,这是处理此类问题的标准方法。