Dask Distributed按顺序执行任务

时间:2018-06-22 17:31:30

标签: dask dask-distributed

我有一个与LocalCluster合作的管道:

from distributed import Client
client = Client()

list_of_queries = [...]  # say 1_000 queries

loaded_data = client.map(sql_data_loader, list_of_queries)

processed_data = client.map(data_processor, loaded_data)

writer_results = client.map(data_writer, processed_data)

results = client.gather(writer_results)

一切正常,但不尽如人意。

看着仪表板的状态页面,我看到这样的东西:

sql_data_loader             900 / 1000
data_processor                0 / 1000
data_writer                   0 / 1000

即与“并行”相反,任务是顺序执行的。结果,data_processor在所有1000个查询都加载完毕后才开始执行。 data_writer等到“ data_processor”完成对所有期货的处理。

根据以前的经验,使用dask.delayed代替client.map 预期的行为类似于:

sql_data_loader              50 / 1000
data_processor               10 / 1000
data_writer                   5 / 1000

这是一个错误的期望,还是我缺少如何设置管道以确保行为类似于dask.delayed的东西?

1 个答案:

答案 0 :(得分:1)

如果您一个接一个地运行地图,那么所有内容都应该流水线。

两个预期目标之间存在一些矛盾:

  1. 任务应根据需要进行流水处理
  2. 首先提交的任务应具有更高的优先级

为了在这两个目标之间取得平衡,Dask根据呼叫之间的延迟分配策略。如果两个映射调用彼此紧接发生,则Dask假定它们属于同一计算,但是如果它们相隔很长时间,则Dask假定它们是不同的计算,因此优先考虑较早的任务。您可以使用fifo_timeout关键字

进行控制
client.map(f, ..., fifo_timeout='10 minutes')

这里是相关的documentation page

以下是显示将地图调用捆绑在一起时所需行为的示例:

In [1]: from dask.distributed import Client

In [2]: client = Client(processes=False)

In [3]: import time

In [4]: def f(x):
   ...:     time.sleep(0.1)
   ...:     print('f', x)
   ...:     return x
   ...: 

In [5]: def g(x):
   ...:     time.sleep(0.1)
   ...:     print('g', x)
   ...:     return x
   ...: 

In [6]: futures = client.map(f, range(20))
   ...: futures = client.map(g, futures)
   ...: 

In [7]: f 0
f 1
f 2
f 3
f 5
f 4
f 6
f 7
g 0
g 1
g 3
g 2
g 4
g 5
g 6
g 7
f 8
f 9
f 10
f 11
f 12
g 8
f 13
g 9
g 10
g 11
g 12
f 14
g 13
f 15
f 16
f 17
g 14
f 18
g 15
f 19
g 16
g 17
g 18
g 19