Joblib 嵌套并行执行不使用可用内核

Joblib nested Parallel execution not making use of available cores

通过在外部语句上使用 n_jobs>1 的嵌套 Parallel 语句,嵌套 Parallel 函数似乎是 1 个线程而不是 4 个线程可用的受限资源。 IE。考虑以下高度简化的脚本来重现该问题:

from joblib import Parallel, delayed
import numpy as np

def parallel_in_parallel_test(i):
    a = np.ones((1000,1000))
    for j in range(2000):
        a *= np.random.randn(1000,1000)
    return a.sum()

def parallel_in_parallel_wrapper(j, n_threads=4):
    out2 = Parallel(n_jobs=n_threads)(delayed(parallel_in_parallel_test)(i) for i in range(100))
    return np.array(out2).sum()

out = Parallel(n_jobs=3)(delayed(parallel_in_parallel_wrapper)(j, n_threads=4) for j in range(100))

我原以为 3 个并行进程会产生 4 个进程,从而产生 CPU 使用率为 400%,即每个“父进程”4 cores/threads。但是,这 4 个“子进程”运行 不是并行的。每个“父进程”使用 100% 的 CPU 而不是 400%(只有一个 core/thread)

考虑以下来自 htop 的屏幕截图:

我可以在极简环境中重现问题:

conda create --name py39 python=3.9
conda activate py39
conda install numpy joblib

我的 OS:Ubuntu 18.04.5 LTS

非嵌套方法对我的特定代码不可行,因为嵌套并行位于 class.

的方法中

对如何正确利用可用资源有什么建议吗?这只是一个简单的错误吗?

显然更改嵌套语句中使用的后端的 inner_max_num_threads 限制有效 - 我仍然不清楚为什么这首先是必要的。

from joblib import Parallel, delayed, parallel_backend
import numpy as np

def parallel_in_parallel_test(i):
    a = np.ones((1000,1000))
    for j in range(2000):
        a *= np.random.randn(1000,1000)
    return a.sum()

def parallel_in_parallel_wrapper(j, n_threads=4):
    with parallel_backend("loky", inner_max_num_threads=n_threads):
        out2 = Parallel(n_jobs=n_threads)(delayed(parallel_in_parallel_test)(i) for i in range(100))
    return np.array(out2).sum()

out = Parallel(n_jobs=3)(delayed(parallel_in_parallel_wrapper)(j, n_threads=4) for j in range(100))