Python 多处理:有和没有池

Python multiprocessing: with and without pooling

我试图了解 Python 的多处理,并设计了以下代码来测试它:

import multiprocessing

def F(n):
    if n == 0: return 0
    elif n == 1: return 1
    else: return F(n-1)+F(n-2)

def G(n):
    print(f'Fibbonacci of {n}: {F(n)}')

processes = []
for i in range(25, 35):
    processes.append(multiprocessing.Process(target=G, args=(i, )))

for pro in processes:
    pro.start()

当我运行它的时候,我告诉我计算时间大约是6.65s。

然后我写了下面的代码,我认为它在功能上等同于后者:

from multiprocessing.dummy import Pool as ThreadPool

def F(n):
    if n == 0: return 0
    elif n == 1: return 1
    else: return F(n-1)+F(n-2)

def G(n):
    print(f'Fibbonacci of {n}: {F(n)}')

in_data = [i for i in range(25, 35)]

pool = ThreadPool(10)

results = pool.map(G, in_data)

pool.close()
pool.join()

而它的运行宁时间将近12s。

为什么第二个几乎是第一个的两倍?他们不应该是等价的吗?

(注意。我是 运行ning Python 3.6,但也在 3.52 上测试了类似的代码,结果相同。)

第二个花费的时间是第一个的两倍的原因可能是由于 CPython 全局解释器锁。

来自http://python-notes.curiousefficiency.org/en/latest/python3/multicore_python.html

[...] the GIL effectively restricts bytecode execution to a single core, thus rendering pure Python threads an ineffective tool for distributing CPU bound work across multiple cores.

如您所知,multiprocessing.dummythreading 模块的包装器,因此您创建的是线程,而不是进程。全局解释器锁,这里有一个 CPU 绑定任务,与简单地在单个线程中顺序执行斐波那契计算没有太大区别(除了你已经添加了一些 thread-management/context-switching 开销)。

在 "true multiprocessing" 版本中,每个进程中只有一个线程,每个线程都使用自己的 GIL。因此,您实际上可以利用多个处理器来提高速度。

对于这个特定的处理任务,没有使用多线程优于多进程的显着优势。如果您只有一个处理器,那么在单个 thread/process 上使用 either 多个进程 多个线程没有任何优势(在事实上,两者都只是为您的任务增加了上下文切换开销。

(FWIW:multiprocessing 版本中的 join 显然是由 python 运行时自动完成的,因此添加显式 join 似乎没有使用 time(1) 对我的测试有任何影响。顺便说一下,如果你 确实 想要添加 join,你应该添加一个 join 处理的第二个 循环。将 join 添加到现有循环将简单地序列化您的进程。)