我有一个与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
的东西?
答案 0 :(得分:1)
如果您一个接一个地运行地图,那么所有内容都应该流水线。
两个预期目标之间存在一些矛盾:
为了在这两个目标之间取得平衡,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