为什么 Dask 执行速度如此之慢,而多处理执行速度却如此之快?

3 python parallel-processing parallelism-amdahl dask

为了更好地理解并行,我比较了一组不同的代码。

这是基本的(code_piece_1)。

for循环

import time

# setup
problem_size = 1e7
items = range(9)

# serial
def counter(num=0):
    junk = 0
    for i in range(int(problem_size)):
        junk += 1
        junk -= 1
    return num

def sum_list(args):
    print("sum_list fn:", args)
    return sum(args)

start = time.time()
summed = sum_list([counter(i) for i in items])
print(summed)
print('for loop {}s'.format(time.time() - start))
Run Code Online (Sandbox Code Playgroud)

此代码以串行方式(for 循环)运行时间消耗者并得到此结果

sum_list fn: [0, 1, 2, 3, 4, 5, 6, 7, 8]
36
for loop 8.7735116481781s
Run Code Online (Sandbox Code Playgroud)

多重处理

多处理风格是否可以被视为实现并行计算的一种方式?

我认为是的,因为医生是这么说的。

这是code_piece_2

import multiprocessing
start = time.time()
pool = multiprocessing.Pool(len(items))
num_to_sum = pool.map(counter, items)
print(sum_list(num_to_sum))
print('pool.map {}s'.format(time.time() - start))
Run Code Online (Sandbox Code Playgroud)

该代码以多处理方式运行同一时间的消费者并得到了这个结果

sum_list fn: [0, 1, 2, 3, 4, 5, 6, 7, 8]
36
pool.map 1.6011056900024414s
Run Code Online (Sandbox Code Playgroud)

显然,在这种特殊情况下,多处理比串行处理更快。

达斯克

Dask是一个灵活的 Python 并行计算库。

这段代码(code_piece_3)与 Dask 运行相同的时间消费者(我不确定我是否以正确的方式使用 Dask。)

@delayed
def counter(num=0):
    junk = 0
    for i in range(int(problem_size)):
        junk += 1
        junk -= 1
    return num
@delayed
def sum_list(args):
    print("sum_list fn:", args)
    return sum(args)

start = time.time()
summed = sum_list([counter(i) for i in items])
print(summed.compute())
print('dask delayed {}s'.format(time.time() - start))
Run Code Online (Sandbox Code Playgroud)

我有

sum_list fn: [0, 1, 2, 3, 4, 5, 6, 7, 8]
36
dask delayed 10.288054704666138s
Run Code Online (Sandbox Code Playgroud)

我的CPU有6个物理核心

问题

为什么 Dask 执行速度如此之慢,而多处理执行速度却如此之快?

我使用 Dask 的方式是否错误?如果是,正确的方法是什么?

注:请结合本案例或其他具体案例进行讨论。请不要泛泛而谈。

Arc*_*ast 5

在您的示例中,dask 比 python 多处理慢,因为您没有指定调度程序,因此 dask 使用默认的多线程后端。正如 mdurant 所指出的,您的代码不会释放 GIL,因此多线程无法并行执行任务图。

请查看此处,了解该主题的详细概述:https ://docs.dask.org/en/stable/scheduler-overview.html

对于您的代码,您可以通过调用以下命令切换到多处理后端: .compute(scheduler='processes')

如果使用多处理后端,进程之间的所有通信仍然需要通过主进程。因此,您可能还想查看分布式调度程序,其中工作进程可以直接相互通信,这对于复杂的任务图尤其有益。此外,分布式调度程序支持工作窃取以平衡进程之间的工作,并具有提供一些有关正在运行的任务的诊断信息的 Web 界面。即使您只想在本地计算机上进行计算,使用分布式调度程序而不是多处理调度程序通常更有意义。