celery 4.4.5使用备注 (一)

选择中间人

celery需要一个单独的服务用于接受和发送消息,这个服务称为’消息中间件’。
假设使用redis作为中间件,
task.py:

from celery import Celery

app = Celery('task', broker='redis://localhost//')

@app.task
def add(x, y):
    return x + y

上面的代码实例化了一个Celery实例。为了在别的模块使用该实例作为创建异步任务、管理任务执行者的入口,这个实例必须时可以的引用的。
第一个参数是Celery实例所在的模块名称,这个参数是必需的,用于在__main__模块创建任务时自动生成名称。
这里同时定义了一个名为add的任务。

运行Celery任务执行者服务器

celery -A tasks worker --loglevel=info

调用异步任务

打开另一个终端

>>> from task import add
>>> add.delay(4, 4)

当前任务由刚才运行的任务执行者运行,检查前一个终端即可看到运行过程。
使用delay方法调用函数会返回AsyncResult类型的实例,该实例可用于检查任务状态,等待任务执行结果,或者获取任务的返回结果。如果任务失败,也可以通过这个实例获取异常和异常回溯。
任务结果默认不可用,可以配置backend参数以远程调用或追溯任务:

app = Celery('task', backend='redis://', broker='redis://')

可以使用get方法获取任务结果,并用timeout参数指定等待时间:

res.get(timeout=10)

get方法会抛出任务抛出的异常,通过指定propagate参数为False,可以避免异常。
也可以通过traceback属性获取异常追溯
结果后台会为了存储或传输结果会占用资源,必须对每个AsyncResult实例调用get()或forget()方法以释放资源。

配置

可以直接设置app的配置:

app.conf.task_serializer = 'json'

app.conf.update(
    task_serializer='json',
    accept_content=['json'],  # Ignore other content
    result_serializer='json',
    timezone='Europe/Oslo',
    enable_utc=True,
)

也可以时用专门的配置文件:

app.config_from_object('celeryconfig')

配置文件大致如下

broker_url = 'pyamqp://'
result_backend = 'rpc://'

task_serializer = 'json'
result_serializer = 'json'
accept_content = ['json']
timezone = 'Europe/Oslo'
enable_utc = True

在项目中使用celery

项目结构:

proj/__init__.py
    /celery.py
    /tasks.py

proj/celery.py

from __future__ import absolute_import, unicode_literals

from celery import Celery

app = Celery('proj',
             broker='redis://',
             backend='redis://',
             include=['proj.tasks'])

# Optional configuration, see the application user guide.
app.conf.update(
    result_expires=3600,
)

if __name__ == '__main__':
    app.start()

celery.py模块创建了一个Celery实例,在项目中引用这个实例即可创建异步任务。

  • include 参数指定了任务执行者启动时要引入的模块。引入后任务执行者才能找到任务。
    proj/tasks.py
from __future__ import absolute_import, unicode_literals

from .celery import app


@app.task
def add(x, y):
    return x + y


@app.task
def mul(x, y):
    return x * y


@app.task
def xsum(numbers):
    return sum(numbers)

在proj的上层目录使用celery程序即可启动任务执行者:

$ celery -A proj worker -l info

--------------- [email protected] v4.0 (latentcall)
--- ***** -----
-- ******* ---- [Configuration]
- *** --- * --- . broker:      amqp://guest@localhost:5672//
- ** ---------- . app:         __main__:0x1012d8590
- ** ---------- . concurrency: 8 (processes)
- ** ---------- . events:      OFF (enable -E to monitor this worker)
- ** ----------
- *** --- * --- [Queues]
-- ******* ---- . celery:      exchange:celery(direct) binding:celery
--- ***** -----

celery默认以CPU数量启动任务执行者的进程数,可以通过celery worker -c指定任务执行者的数量。如果任务中主要是I/O操作,可以考虑增加worker的数量。否则并不能显著提高执行效率,甚至可能降低性能。
celery也支持多线程

–app参数指定celery实例,值的格式module.path:attribute
对于–app=proj,celery会按如下顺序搜索相关实例:

  1. 名为proj.app的参数
  2. 名为proj.celery的参数
  3. proj模块中值为Celety应用的参数
  4. 名为proj.celety.app的参数
  5. 名为proj.celery.celery的参数
  6. 模块proj.celery中值为Celery应用的参数

调用任务

delay()方法实际上是apply_async()的缩写。apply_async()允许指定任务的执行时间(countdown)以及任务的调用队列(queue)等:

res = add.apply_async((2, 2), queue='lopri', countdown=10)
# 检查任务状态
res.state  # 'FAILURE'
# 获取任务id
res.id  # 'd6b3aea2-fb9b-4ebc-8da4-848818db9114'
# 获取AsyncResult实例
from proj.celery import app
res = app.AsyncResult('d6b3aea2-fb9b-4ebc-8da4-848818db9114')

任务常见状态:
PENDING -> STARTED -> SUCCESS
PENDING状态实际上是未知任务的默认状态。
只有设置了task_track_started参数或在装饰其中指定@task(track_started=True)才会有STARTED状态。

流式调用

当希望将任务签名传递给另一个进程或作为另一个函数的参数时,可以使用signatures。

sa = add.signature((2, 2), countdown=10)
# 调用
res = sa.delay()
res.get()
groups

groups将一组任务同时调用,并成组返回结果

from celery import group
from proj.tasks import add

group(add.s(i, i) for i in range(10)),get()  # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

g = group(add.s(i) for i in range(10))
g(10).get()  # [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
chains

任务也可以连接起来依次调用

from celery import chain
from proj.tasks import add, mul
chain(add.s(4, 4) | mul.s(8))().get()
chords

chrods是有回调函数的组

from celery import chord
from proj.tasks import add, xsum
chord((add.s(i, i) for i in range(10)), xsum.s())().get()

当一个组与另一个任务组成链条时,自动转为chord

(group(add.s(i, i) for i in range(10)) | xsum.s())().get()

任务路由

celery支持通过名称分配任务给指定的任务队列

app.conf.update(
    task_routes = {
        'proj.tasks.add': {'queue': 'hipri'},
    },
)

也可以通过在运行任务时指定apply_async参数指定任务队列

from proj.tasks import add
add.apply_async((2, 2), queue='hipri')

再通过命令行参数-Q指定任务执行者执行队列中的任务

celery -A proj worker -Q hipri

使用逗号选择多个队列

celery -A proj worker -Q hipri,celery

猜你喜欢

转载自blog.csdn.net/JosephThatwho/article/details/106785696
今日推荐