2

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

这是基本的(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))

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

sum_list fn: [0, 1, 2, 3, 4, 5, 6, 7, 8]
36
for loop 8.7735116481781s

多处理

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

我假设是的,因为文档是这样说的。

这是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))

此代码以多处理方式运行同一时间消费者并得到此结果

sum_list fn: [0, 1, 2, 3, 4, 5, 6, 7, 8]
36
pool.map 1.6011056900024414s

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

达斯克

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))

我有

sum_list fn: [0, 1, 2, 3, 4, 5, 6, 7, 8]
36
dask delayed 10.288054704666138s

我的 cpu 有 6 个物理核心

问题

为什么 Dask 执行得这么慢,而多处理执行得这么快?

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

注:请与本案例或其他具体具体案例讨论。请不要泛泛而谈。

4

3 回答 3

3

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

在这里查看有关该主题的良好概述:https ://docs.dask.org/en/stable/scheduler-overview.html

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

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

于 2019-09-07T10:30:06.167 回答
1

为什么并行计算比串行计算花费更长的时间?

因为有更多的指令加载到 CPU 上来执行(甚至在指令/预期的计算块的第一步首先进入 CPU 之前“非常”很多),然后在纯粹的[SERIAL]情况下,没有附加成本被添加到执行流程中。

对于这些(从源代码中隐藏)附加操作(您在[TIME]-domain(此类“准备”的持续时间)和-domain(分配更多 RAM 以包含-operated 代码[SPACE]所需的所有相关结构)支付[PARALLEL],通常是仍然刚刚运行的[CONCURRENT]代码,如果我们在术语上学究且准确),这又会花费您[TIME],因为每个 RAM-I/O 花费您大约 1/3 以上[us] ~ 300~380 [ns]

结果?

除非您的工作负载包具有“足够”的工作量,否则可以并行执行(非阻塞,没有锁,没有互斥体,没有共享,没有依赖关系,没有 I/O,......确实是独立的,具有最小值RAM-I/O 重新获取),很容易“付出比你得到的多得多的钱”

有关附加成本和对结果加速产生如此强烈影响的事物的详细信息,请在此处开始阅读对使用 Amdahl 定律的原始、开销幼稚公式的盲目批评

于 2019-09-06T11:17:46.083 回答
1

您拥有的代码需要 GIL,因此一次只运行一个任务,而您得到的只是额外的开销。例如,如果您使用带有进程的分布式调度程序,那么您将获得更好的性能。

于 2019-09-06T15:04:01.883 回答