Python 多进程池 API 在进程数和工作线程数增加时无法高效工作

Python multiprocessing Pool API doesn't work efficiently when process count and worker count increased

我正在尝试应用多处理来并行化我的代码。我还有大约 2000 件作品 需要完成。由于创建 2000 个并发进程是不切实际的,因此我使用 python multiprocessing.pool API 在管理任务队列时使工作并行化.我尝试创建 100 个工人。但是需要几个小时才能完成,与顺序实施相比,这并不是一个很大的收获。我的笔记本电脑有 12 个逻辑核心。然后我尝试 同时增加 workers 和 works 。从技术上讲,完成每项工作应该花费相同的时间,因为我每次只将一项工作分配给一名工人。但是我发现,即使每个工作的工作负载没有改变,整个过程的时间也会增加。 API 有什么问题吗?还是我做错了?有人可以为我的 2000 个作品提供一个可能的解决方案,以便使用 Python 在最短时间内并行处理吗?

P.S: 由于代码实现问题,我无法使用多线程。

我的代码

inputListLen = 13
workerCount = 13
regressList = regressList[:inputListLen] # regressList has 2000 items
with Pool(processes=workerCount) as pool:
    print(pool.map(runRegressWriteStatus, regressList))

结果

Input List Len  | workers   | Time(seconds) 
1               | 1         | 4.5  
2               | 2         | 4.9  
3               | 3         | 5.4  
4               | 4         | 5.6  
5               | 5         | 6.3  
6               | 6         | 7.2  
7               | 7         | 8.3  
8               | 8         | 9.6  
9               | 9         | 10.0 
10              | 10        | 10.7 
11              | 11        | 11.6 
12              | 12        | 11.8 
13              | 13        | 13.3 

我认为你误解了一些事情,一些事情的假设并不准确。正如我在此处提到的 ,您实际上可以 运行 与 multiprocessing 并行的进程数取决于系统上的 cpu 核心数并由其控制。它是实际的物理核心,而不是您在启用超线程时看到的逻辑核心。

所以 12 个逻辑核心意味着 6 个物理核心,每个核心 2 个线程为您提供 12 个逻辑核心。因此,在任何时候你的内核都会看到 12 个逻辑内核,它会尝试安排 12 个进程,但系统只有 6 个物理内核,所以有很多上下文切换恰好使它看起来像有 12 个内核,但在任何时间点实时不能超过6个进程,因为记住你只有6个核心。

其次,Pool 的工作方式与 Process 不同,而使用 Process,您可以启动并行进程来执行可能彼此独立的任务。

Pool 有不同的目的,使用 Pool 对象,您正在创建一个 pool 进程,然后将一个大的 task/input 传递给它,然后 pool 将这个大的 task/input 分成较小的一个,并将其分配给可以同时对较小的输入进行操作的 processes

这是一个非常简单的示例,说明如何使用 pool

import multiprocessing as mp
import time


def f(x):
    res = 0
    for i in range(x):
        res += i ** 6


if __name__ == '__main__':
    t1 = time.time()
    # MP Pool creates 4 concurrent processes and run the same function with diffrent args, to achieve the parallel computation
    po = mp.Pool(processes=4)
    res = po.map(f, range(5000))
    po.close()
    po.join()
    print('Parallel execution time taken = {}'.format(time.time() - t1))

    t2 = time.time()
    seq_res = list(map(f, range(5000)))
    print('Sequential execution time taken = {}'.format(time.time() - t2))

(py37) rbhanot@rbhanotlinux ~/home » python 7-1.mppool.py
Parallel execution time taken = 0.91422438621521
Sequential execution time taken = 2.9315543174743652
(py37) rbhanot@rbhanotlinux ~/home » 

如您所见,pool 的并行执行比顺序执行花费的时间少 3 倍。

现在我有 8 个逻辑内核,但我的机器上只有 4 个物理内核,而且我的内核最多只能一次调度 4 个进程,因此创建一个超过 4 个进程的池不会有任何区别,这里就是证明。

当 运行 有 7 个进程的池时

Parallel execution time taken = 0.9177846908569336

当 运行 有 12 个进程的池时

Parallel execution time taken =  0.9213907718658447

当 运行 有 2 个进程的池时

Parallel execution time taken = 1.712911605834961