dask.bag,我应该如何在相同的数据上有效地运行多个计算

时间:2017-02-20 17:07:34

标签: dask

我正在处理大量数据,大部分时间用于加载数据和解析json /等等。我想使用单次扫描收集整个数据集的简单统计信息。

我希望我可以使用以下模式在计算中使用图表简化:

parsed = read_text(files).map(parsing)
example_stat_future = parsed.map(foo).frequencies()
another_stat_future = parsed.map(bar).sum()
etc.
example_stat, another_stat = compute(example_stat_future, another_stat_future)

但是在尝试时我看到极度减速。这是我的示例代码:

from json import loads, dumps
from time import time
import dask.bag as db

print("Setup some dummy data")
for partition in range(10):
    with open("/tmp/issue.%d.jsonl" % partition, "w") as f_out:
        for i in range(100000):
            f_out.write(dumps({"val": i, "doubleval": i * 2}) + "\n")


print("Running as distinct computations")
loaded = db.read_text("/tmp/issue.*.jsonl").map(loads)
first_val = loaded.pluck("val").sum()
second_val = loaded.pluck("doubleval").sum()
start = time()
first_val.compute()
print("First value", time() - start)
start = time()
second_val.compute()
print("Second value", time() - start)


print("Running as a single computation")
loaded = db.read_text("/tmp/issue.*.jsonl").map(loads)
first_val = loaded.pluck("val").sum()
second_val = loaded.pluck("doubleval").sum()
start = time()
db.compute(first_val, second_val)
print("Both values", time() - start)

输出

在拥有数百万件物品的数据集上,我从未完成过一次跑步,然后再花费太长时间杀死它。

Setup some dummy data
Running as distinct computations
First value 0.7081761360168457
Second value 0.6579079627990723
Running as a single computation
Both values 37.74176549911499

是否有解决此类问题的常见模式?

1 个答案:

答案 0 :(得分:2)

简短回答

导入并运行以下内容,事情应该更快

from dask.distributed import Client
c = Client()

确保已安装dask.distributed

conda install dask distributed -c conda-forge
# or 
pip install dask distributed --upgrade

虽然请注意,您必须在文件底部的if __name__ == '__main__':块内而不是顶层执行此操作:

from ... import ...

if __name__ == '__main__':
    c = Client()
    # proceed with the rest of your dask.bag code

答案很长

Dask有各种各样的调度程序。 Dask.bag默认使用多处理调度程序,但可以轻松地使用其他调度程序。有关详细信息,请参阅this doc

多处理调度程序在单独的进程中工作,然后在必要时将这些结果带回主进程。对于像b.map(...).filter(...).frequencies()这样的简单线性工作负载,任务都可以融合到一个单个任务中,该任务进入一个进程,计算,然后只返回一个非常小的结果。

但是,当工作负载具有任何类型的分支(例如您描述)时,多处理调度程序必须将数据发送回主进程。根据数据的不同,这可能很昂贵,因为我们需要在对象在进程之间移动时序列化对象。 Dask中的基本多处理调度程序没有数据局部性的概念。一切都由中央过程协调。

幸运的是,Dask's distributed scheduler更加智能,可以轻松应对这些情况。当您在没有任何参数的情况下运行dask.distributed.Client()时,您将在计算机上创建一个本地“集群”进程。这有许多其他优点;例如,如果您导航到https://localhost:8787/status,您将被视为所有计算中正在运行的dashboard