子级任务:

说明: 前面学习的任务调用基本上已够用,但有时业务场景可能需要任务关联,且子任务可能需要父任务为其传递一些必要参数,此时可通过func.subtask或简写func.s实现,子任务对象依然可以调用任务对象的API,delay和apply_async,但和常规调用不同的是子任务调用时传递的参数加生成子任务时初始化参数的才是最终任务的参数,所以子任务在调用时就不需要再重复传递子任务初始化时的参数了.


>>> mail = send_mail.subtask(('sub', 'msg'), countdown=1)
>>> mail.delay('limanman')
<AsyncResult: de491985-5170-43c3-905f-f899f3aef460>
或
>>> mail = send_mail.s('sub', 'msg', countdown=1)
>>> mail.delay('limanman')
<AsyncResult: c67194e0-16e1-47a8-a4bb-420f4966b7f1>

注意: send_mail.subtask(('sub', 'msg'), countdown=1)或send_mail.s('sub', 'msg', countdown=1)返回的是Signature对象,此对象携带生成子任务时的参数,且可调用任务对象的API,当调用时,传递的参数被提前.


原语操作:

# 使组式:


>>> from celery import group
>>> group(send_mail.s(i, i, i) for i in xrange(10))().get()
>>> group(send_mail.s('msg_{0}'.format(i)) for i in xrange(10))('usr', 'sub').get()

说明: group内部使用列表生成式生成了10个子任务,生成时且提供了一个参数,当调用group('usr', 'sub')时其实是遍历group内部的所有子任务调用其.delay('usr', 'sub'),所以是并发异步执行的,上面说过,调用时传递的参数会被提前,所以其实最终的参数顺序是'usr', 'sub', 'msg_{0}'.format(i),异步返回的是GroupResult对象,如果要获取每个子任务的结果,可通过同步阻塞的get方法获取.


# 使链式:


>>> from celery import chain
>>> result = chain(add.s(2) | add.s(1))(5)
>>> result.get()
>>> result.parent.get()
>>> result.parent.parent.get()

说明: chain内部两个链式子任务,|表示前一个的输出作为另一个的输入,当调用chain(...)(5)时,其实是首先调用add.s(2).delay(5)计算出结果为7,然后|传递作为add.s(1)的输入,其实是调用add.s(1).delay(7)

计算出结果为8,异步返回的是AsyncResult对象,可通过同步阻塞的get方法获取,链式操作还有一个特别的地方可通过result.parent.get()获取上层结果.


# 使回调:


>>> from celery import chain group chord
>>> chord((send_mail.s('usr_{0}'.format(i), 'sub_{0}'.format(i), 'msg_{0}'.format(i)) for i in xrange(10)), send_mail.s('sub', 'msg'))().get()
>>> chain(group(send_mail.s('usr_{0}'.format(i), 'sub_{0}'.format(i), 'msg_{0}'.format(i)) for i in xrange(10))|send_mail.s('sub', 'msg'))().get()

说明: chord和group类似,只是在此基础上加了个回调,当调用get方法时会对,第一个参数必须是一个包含子任务的可迭代对象,第二个为可回调函数或方法,会自动接收提前参数,其实用chain和group也可以利用如上方式实现类似回调.