异步实时并行分布式Dask

异步实时并行分布式Dask,dask,dask-distributed,Dask,Dask Distributed,我正在阅读关于dask.distributed的文档,看起来我可以通过client.submit()向分布式集群提交函数 我有一个现有函数some_func,它异步抓取单个文档(比如,文本文件),我想获取原始文档,抓取所有不包含元音的单词,并将其推回到另一个数据库中。此数据处理步骤是阻塞的 假设有数百万个文档,分布式集群只有10个节点和1个可用进程(即一次只能处理10个文档),dask.distributed将如何处理需要处理的文档流 下面是一些示例代码: client = dask.distr

我正在阅读关于
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个文档后内存不足


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

调用submit时,所有参数都被序列化并立即发送到调度程序。另一种方法是获取文档并在集群上处理它们(这假设文档对所有工作人员都是全局可见的)


如果文档仅在客户端机器上可用,并且您想限制流,那么您可以考虑使用DASK队列或ASSRead迭代器。

< P>使用DASK队列,下面是使用分布式集群的DASK队列(基于)的修改示例:


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

分布式dask是否与asyncio.queue兼容?我放入队列的项目是来自aiohttp的http响应。虽然http请求是异步的,但我认为将
put
放入
queue.queue
的响应是同步的。对于返回大json文件的aiohttp响应,将此响应发送给dask工作进程(通过
q.put(response['json'])
)是缓慢且阻塞的。有没有办法使其成为同步的?您可以在异步模式下运行dask。它在tornado事件循环上运行(今天也是asyncio事件循环),请参阅
for fn in filenames:
    doc = client.submit(retrieve_doc, fn)
    process = client.submit(process_doc, doc)
    fire_and_forget(process)
#!/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)