如何在自定义dask图中调用Executor.map?

时间:2016-09-02 08:47:43

标签: python-2.7 anaconda distributed distributed-computing dask

我有一个计算,包括3个“地图”步骤,最后一步取决于前两个的结果。我正在使用在多台PC上运行的dask.distributed来执行此任务。

依赖关系图如下所示。

map(func1, list1) -> res_list1-\
                                | -> create_list_3(res_list1, res_list2)-> list3 -> map(func3, list3)
map(func2, list2) -> res_list2-/

如果我们想象这些计算是独立的,那么可以直接调用map函数3次。

from distributed import Executor, progress

def process(jobid):
    e = Executor('{address}:{port}'.format(address=config('SERVER_ADDR'),
                                           port=config('SERVER_PORT')))
    futures = []
    futures.append(e.map(func1, list1))
    futures.append(e.map(func2, list2))
    futures.append(e.map(func3, list3))

    return futures

if __name__ == '__main__':
    jobid = 'blah-blah-blah'
    r = process(jobid)
    progress(r)

但是,list3是根据func1func2的结果构建的,其创建不容易map pable(list1,{{1} },list2res_list1存储在Postgresql数据库中,res_list2的创建是list3查询,需要一些时间。)

我试图将JOIN的号码添加到期货列表中,但是,这种方法没有按预期运行:

submit

在这种情况下,一个def process(jobid): e = Executor('{address}:{port}'.format(address=config('SERVER_ADDR'), port=config('SERVER_PORT'))) futures = [] futures.append(e.map(func1, list1)) futures.append(e.map(func2, list2)) futures.append(e.submit(create_list_3)) futures.append(e.map(func3, list3)) return futures 已收到执行dask-worker的任务,但其他人同时收到了调用create_list_3的任务,这些任务有错误,因为func3没有存在。

明显的事情 - 我缺少同步。工人必须停下来等待list3的创建完成。

list3的文档描述了可以提供同步的自定义任务图。

但是,文档中的示例不包含dask个函数,只包含简单的计算,例如调用mapadd

在我的情况下是否可以使用inc和自定义dask图表,还是应该使用map中未包含的其他方法实现同步?

1 个答案:

答案 0 :(得分:1)

如果要链接任务之间的依赖关系,则应将先前任务的输出传递给另一个任务的输入。

futures1 = e.map(func1, list1)
futures2 = e.map(func2, list2)
futures3 = e.map(func3, futures1, futures2)

对于func3的任何调用,Dask将处理等待直到输入准备就绪,并将从计算的任何地方向该函数发送适当的结果。

但是,您似乎希望通过其他一些自定义方式处理数据传输和同步。如果是这样,那么将一些令牌传递给func3的调用可能会很有用。

futures1 = e.map(func1, list1)
futures2 = e.map(func2, list2)

def do_nothing(*args):
    return None

token1 = e.submit(do_nothing, futures1)
token2 = e.submit(do_nothing, futures2)

list3 = e.submit(create_list_3)

def func3(arg, tokens=None):
    ...

futures3 = e.map(func3, list3, tokens=[token1, token2])

这有点像黑客,但会迫使所有func3函数等到他们能够从之前的地图调用中获取令牌结果。

但是我建议尝试做第一个选项。这将使dask在运行时更加智能,并且可以释放资源。像token1/2这样的障碍导致次优调度。