[英]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.