分布式Dask,具有异步实时并行性

时间:2018-10-04 21:16:56

标签: dask dask-distributed

我正在阅读dask.distributed上的文档,看来我可以通过client.submit()向分布式集群提交功能了。

我有一个现有的函数some_func,该函数异步获取单个文档(例如,文本文件),我想获取原始文档并获取所有不包含元音的单词,然后将其推回一个不同的数据库。此数据处理步骤正在阻止。

假设有数百万个文档,并且分布式集群中只有10个节点具有1个进程可用(即,一次只能处理10个文档),那么dask.distributed将如何处理所需的文档流处理?

下面是一些示例代码:

client = dask.distributed('tcp://1.2.3.4:8786')

def some_func():
    doc = retrieve_next_document_asynchronously() 
    client.submit(get_vowelless_words, doc)

def get_vowelless_words(doc):
    vowelless_words = process(doc)
    write_to_database(vowelless_words)

if __name__ == '__main__':
    for i in range(1000000):
        some_func()

由于文档的处理正在阻塞,并且群集只能同时处理10个文档,因此在群集繁忙时检索到另外30个文档会发生什么情况?我了解client.submit()是异步的,它将返回并发的将来,但是在这种情况下会发生什么?它会将文档保存在内存中直到1/10内核可用,并且有可能导致机器在等待1000个文档之后耗尽内存。

在这种情况下,调度程序会做什么?先进先出?我是否应该以某种方式更改代码,以便它在检索下一个文档之前等待内核可用?如何实现?

2 个答案:

答案 0 :(得分:0)

当您调用Submit时,所有参数都被序列化并立即发送到调度程序。另一种选择是既获取文档又在群集上对其进行处理(假定文档对所有工作人员都是全局可见的)。

for fn in filenames:
    doc = client.submit(retrieve_doc, fn)
    process = client.submit(process_doc, doc)
    fire_and_forget(process)

如果文档仅在客户端计算机上可用,并且您想限制流量,那么您可以考虑使用dask Queue或as_completed迭代器。

答案 1 :(得分:0)

要将队列与dask一起使用,以下是将dask Queue与分布式集群(基于documentation)结合使用的修改示例:

#!/usr/bin/env python

import distributed
from queue import Queue
from threading import Thread

client = distributed.Client('tcp://1.2.3.4:8786')
nprocs = len(client.ncores())

def increment(x):
    return x+1

def double(x):
    return 2*x

input_q = Queue(maxsize=nprocs)
remote_q = client.scatter(input_q)
remote_q.maxsize = nprocs
inc_q = client.map(increment, remote_q)
inc_q.maxsize = nprocs
double_q = client.map(double, inc_q)
double_q.maxsize = nprocs
result_q = client.gather(double_q)

def load_data(q):
    i = 0
    while True:
        q.put(i)
        i += 1

load_thread = Thread(target=load_data, args=(input_q,))
load_thread.start()

while True:
    size = result_q.qsize()
    item = result_q.get()
    print(item, size)

在这种情况下,我们明确地将每个队列的最大大小限制为等于可用的分布式进程的数量。否则,while循环将使群集过载。当然,您也可以将maxsize调整为可用进程数的倍数。对于增量和双精度之类的简单函数,我发现maxsize = 10*nprocs仍然是合理的,但这肯定会受到运行自定义函数所花费时间的限制。