Python 进程和线程如何映射到硬件线程?

How do Python processes and threads map onto hardware threads?

我的问题与 this one 类似,但我正在寻找有关其工作原理的最新信息:

假设 CPU 具有 4 个内核和 8 个线程,例如,并给出以下代码:

from multiprocessing.dummy import Pool as ThreadPool
from multiprocessing import Pool as ProcessPool


with ThreadPool(number_of_threads) as pool:
    pool.map(some_function, some_iterable)

with ProcessPool(number_of_processes) as pool:
    pool.map(some_function, some_iterable)

我想知道这些线程和进程将如何映射到 CPU 内核和线程(如果有的话)。例如:

我总是将 ThreadPool 用于 IO 绑定,将 ProcessPool 用于 CPU 绑定。使用 ProcessPool,我发现使用与 CPU 内核相同的 number_of_processes 效果很好。但是我不知道 ThreadPool 应该是什么基准。

我认为一个重要的免责声明是:理论上 "how it should work" 只能到此为止。对于实际性能比较,即 4、6、8 或任意数量线程的线程池之间的性能差异,唯一具体的答案来自使用实际工作负载对目标系统进行基准测试。

告知此处答案的最重要问题之一是:

Does it make a difference to any of the above whether some_function is IO bound or CPU bound?

这是 IMO 最重要的性能问题。您的工作量是多少 (some_iterable)?是 I/O 绑定还是 CPU 绑定? I/O 绑定正在发出 http 请求,或查询数据库或文件系统。 CPU bound 正在执行某种计算、散列、添加、解析等。大多数工作负载(根据我的经验是混合的,但如果我不得不根据经验说,支持 I/O)。如果工作负载是 I/O 并且 some_iterable 正在执行同步 I/O 那么您很可能可以通过创建更大的工作池来扩展性能,因为大多数时候 process/thread 正在执行等待 I/O!

If number_of_processes is 8, will each process likely end up on a cpu thread?

有点 :p。你有 8 个物理线程。每个池有 8 个 processes/main 线程,加上您正在执行的程序的线程,再加上您的 OS 的所有其他 processes/threads :)。您的处理器已饱和。如果您有 CPU 绑定的工作负载,它们将饱和,并且您可能看不到 7-8 池大小的性能提升。如果您的工作负载受到 I/O 限制,您可能仍会看到性能提高,池大小大于您拥有的处理器数量。

If number_of_threads is 8, will each thread likely end up on a cpu thread?

与上述处理器问题相同。是的,他们很可能会在 CPU 线程中结束。如果您的工作负载受到 I/O 限制,增加池大小可能仍会在一段时间内提高性能。
对于 CPU 绑定的工作负载,这就是事情变得复杂的地方。 Python 的 GIL prevents python from executing multiple python bytecode at once。即使您将有足够的 CPU 物理线程来执行您的程序,但您需要一次只能执行一个线程!如果 CPU 绑定工作负载,number_of_threads = 8 比 CPU 绑定工作负载的 number_of_threads = 4 提供更好的性能,我会感到惊讶!

What are the implications if number_of_threads are much higher than the number of cores/cpu threads?

对于 I/O 绑定的工作负载,什么都没有!根据您的机器调度和执行大量线程的能力或上游服务为您发出的所有请求提供服务的能力,您有时会达到性能限制。对于 CPU 绑定工作负载,请参阅上面的答案(由于 GIL,您会更快地达到限制)。

参考文献:

  • How to utilize all cores with python multiprocessing
  • How to pin different processes to individual cpu cores in Python

另外,根据我主要从事基于 http 的服务的经验,将逻辑核心(硬件线程)视为与物理核心相同,这从来没有让我反感。因此,在您的情况下,我只考虑您有 8 个可用内核。区别是可能对您的工作量不重要(在黑暗中拍摄)?