【问题标题】:Python multiprocessing: with and without poolingPython 多处理:有和没有池化
【发布时间】:2016-12-18 12:44:34
【问题描述】:

我正在尝试了解 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()

它的运行时间几乎是 12 秒。

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

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

【问题讨论】:

  • 你是怎么join第一个版本的?
  • 我没有。我应该有吗?
  • 您如何知道已完成的流程?据我记得,start 不会告诉您该过程何时完成,所以我假设在您显示的内容之后有一些代码。
  • 好吧,没有更多代码了。由于 G(F()) 函数按要求执行,我认为没有任何问题。
  • 确实,如果我在第一版代码的最后一个for循环中添加pro.join,运行时间就会重复。

标签: python-3.x python-multiprocessing


【解决方案1】:

第二个需要两倍于第一个的原因可能是由于 CPython 全局解释器锁。

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

[...] GIL 有效地将字节码执行限制在单核上,从而使纯 Python 线程成为跨多个核分配 CPU 绑定工作的无效工具。

如您所知,multiprocessing.dummythreading 模块的包装器,因此您创建的是线程,而不是进程。具有 CPU 密集型任务的全局解释器锁与在单个线程中按顺序执行斐波那契计算没有太大区别(除了您添加了一些线程管理/上下文切换开销)。

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-08-20
    • 2017-07-25
    • 2017-04-05
    • 2021-07-24
    • 2020-08-14
    • 2016-11-10
    • 2017-04-09
    • 2017-04-18
    相关资源
    最近更新 更多