繁体   English   中英

如何与在多台计算机上运行的芹菜工作者并行处理一组对象?

[英]How to parallelly process a collection of objects with celery workers running on multiple machines?

我在可访问的mongoDB集合中有数十万个文档,这些文档遵循一个称为MyDoc的MongoEngine架构。 在这些文档的每一个上都有一些要运行的东西(我们称其为my_operation)。 另外,my_operation需要(仅读取,不会更改)通过create_data_dict函数构造的名为data_dict的OrderedDict。 而且我希望能够通过芹菜工人并行运行my_operation。

该设置包括django,mongo,mongoengine和celery。

选项1:

@celery.task()
def my_operation(my_doc_list):
   data_dict = create_data_dict()
   for doc in my_doc_list:
       do_something_to_doc(data_dict, doc)
       doc.save()

def create_data_dict():
   #blah blah blah
   return data_dict

#So I run everything like this:
batch_size = len(MyDoc.objects)/no_of_celery_workers
for b in xrange(0, len(MyDoc.objects), batch_size):
    my_operation.delay(MyDoc.objects[b:b+batch_size])

选项2:my_operation采用data_dict和MyDoc实例

@celery.task()
def my_operation(data_dict, my_doc):
   do_something_to_doc(data_dict, my_doc)
   my_doc.save()

def create_data_dict():
   #blah blah blah
   return data_dict

#So I run everything like this:
data_dict = create_data_dict()
celery.group([my_operation.s(data_dict, my_doc) for my_doc in MyDoc.objects]).apply_async()

选项3:

@celery.task()
def my_operation(my_doc):
   data_dict = create_data_dict()
   do_something_to_doc(data_dict, my_doc)
   my_doc.save()

def create_data_dict():
   #blah blah blah
   return data_dict

#So I run everything like this:
celery.group([my_operation.s(my_doc) for my_doc in MyDoc.objects]).apply_async()

选项4:

@celery.task()
def my_operation(my_doc):
   data_dict = get_data_dict()
   do_something_to_doc(data_dict, my_doc)
   my_doc.save()

def create_data_dict():
   #blah blah blah
   return data_dict

def get_data_dict():
   data_dict = cache.get("data_dict")
   if data_dict is None:
        data_dict = create_data_dict()
        cache.set("data_dict", data_dict)
   return data_dict

#So I run everything like this:
celery.group([my_operation.s(my_doc) for my_doc in MyDoc.objects]).apply_async()

如果Option1有效,我可能不会问这个问题,但是,,我无法将查询集响应切片或将查询集本身传递给芹菜工人,因为他们不腌制。 这就是回溯似乎最能说明的内容。

使用Option2时,我最终将在每个任务中传递data_dict,这听起来似乎不太吸引人。 而且,如果我在多台计算机上运行celery worker(我确实打算这样做),则data_dict实际上仅需要传递一次,这将浪费大量网络,而这毫无用处。

在Option3的情况下,将为每个文档重新创建data_dict,这现在看来是对处理能力的巨大浪费。

选项4:我使用缓存来备份data_dict,而不是重新计算或随每个文档重新传输。 这听起来是最好的主意,但有一个陷阱。 下次我想对所有MyDocs进行my_operation时,无论是否在缓存中,我都希望重新计算data_dict。 有办法实现吗?

问题:最佳方法是什么?

从表面上看,选项2听起来就像选项1一样-当您传递对象或其数据时。

这里有很多未知数,但是考虑到您在选项4中提到的情况,可能会有一些缓存争用/竞争条件,我可能会选择每次生成数据并仅传递对象ID,或者如果这样做代价过高,我会实施一个集合来存储缓存的数据,然后清理缓存(findAndModify以停止竞争条件),作为任务的一部分。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM