限制"threads"个数时设置什么?

What am I setting when I limit the number of "threads"?

我有一段使用库 numpy, scipy, sklearn, matplotlib 的大型代码。我需要限制 CPU 的使用以阻止它消耗我的计算集群中的所有可用处理能力。在 this answer 之后,我实现了以下代码块,该代码块在脚本为 运行:

时立即执行
import os
parallel_procs = "4"
os.environ["OMP_NUM_THREADS"] = parallel_procs
os.environ["MKL_NUM_THREADS"] = parallel_procs
os.environ["OPENBLAS_NUM_THREADS"] = parallel_procs
os.environ["VECLIB_MAXIMUM_THREADS"] = parallel_procs
os.environ["NUMEXPR_NUM_THREADS"] = parallel_procs

我的理解是这应该将使用的核心数限制为 4,但显然这并没有发生。这是 htop 为我的用户和脚本显示的内容:

有 16 个进程,其中 4 个 CPU 的百分比显示在 100% 以上。这是 lscpu:

的摘录
CPU(s):              48
On-line CPU(s) list: 0-47
Thread(s) per core:  2
Core(s) per socket:  12
Socket(s):           2

我还在我的代码中使用 multiprocessing 库。我使用 multiprocessing.Pool(processes=4) 设置了相同数量的进程。如果没有上面显示的代码块,脚本坚持使用尽可能多的内核,显然完全忽略了 multiprocessing

我的问题是:当我使用上面的代码时,我限制了什么?我应该如何解释 htop 输出?

(作为评论可能更好,如果出现更好的答案,请随时删除它,因为它基于我使用库的经验。)

我在多处理部分代码时遇到了类似的问题。如果您使用 BLAS 或 MKL 编译库(或者如果您从中提取它们的 conda repo 还包含 BLAS/MKL 库),以加速某些计算。

当 运行 您的脚本在单个进程中时,这很好,因为它会产生线程数达到 OPENBLAS_NUM_THREADSMKL_NUM_THREADS 指定的数量(取决于您是否有BLAS 库或 MKL 库 - 您可以使用 numpy.__config__.show()) 来识别哪个在这种情况下,设置 n=1before importing numpy & scipy)或一些小数字以确保您没有超额订阅是有意义的:

n = '1'
os.environ["OMP_NUM_THREADS"] = n
os.environ["MKL_NUM_THREADS"] = n

如果设置multiprocessing.Pool(processes=4),它将使用4*n个进程(每个进程中有n个线程)。在您的情况下,您似乎有一个包含 4 个进程的池,每个进程启动 4 个线程,因此有 16 个 python 个进程。

htop 输出给出 。由于 Linux 机器将线程解释为 CPU(我这里的术语可能有误),如果每个 CPU 有 4 个线程,则意味着满载实际上是 400 %。这可能不会达到最大值,具体取决于正在执行的操作(以及缓存,因为您的机器看起来是超线程的)。

因此,如果您在单个 process/single 线程中的部分代码中执行 numpy/scipy 操作,则最好设置更大的 n,但对于多处理部分,设置更大的池和单个或小的 n 可能会更好。不幸的是,如果您通过环境标志传递标志,则只能在脚本开头设置一次。如果你想动态设置它,我在某处的 numpy 问题讨论中看到你应该使用 threadpoolctl(如果我能再次找到它,我会添加一个 link)。