Celery简介

说在前面,本文只是对Celery的简单介绍,细节方面有很多不足,大致知道Celery有什么用,应该怎么用,常见的配置怎么配,就行了,具体的还是多看看官方文档或者大神们的文章。

1. Celery是什么?

Celery是一款异步消息队列工具。
使用Celery的常见场景如下:

  1. Web应用。当用户触发的一个操作需要较长时间才能执行完成时,可以把它作为任务交给Celery去异步执行,执行完再返回给用户。这段时间用户不需要等待,提高了网站的整体吞吐量和响应时间。

  2. 定时任务。生产环境经常会跑一些定时任务。假如你有上千台的服务器、上千种任务,定时任务的管理很困难,Celery可以帮助我们快速在不同的机器设定不同种任务。

  3. 同步完成的附加工作都可以异步完成。比如发送短信/邮件、推送消息、清理/设置缓存等。

Celery的架构如下图所示(网上找的):
在这里插入图片描述
其中的消息中间件常用的就是RabbitMQRedis

2. 安装Celery

# -U即--upgrade
$ pip install -U celery

# 安装Celery和捆绑包
pip install "celery[librabbitmq]"
pip install "celery[librabbitmq,redis,auth,msgpack]"

# 源码安装
https://PyPI.org/project/celery/
tar zxvf celery-0.0.0.tar.gz
cd celery-0.0.0
python setup.py build
python setup.py install

3. 使用Celery

3.1 Django和Celery

从Django 3.1以后,就已经集成了Celery,不需要我们在额外安装Celery了。
常见的Django项目结构:

- proj/
  - manage.py
  - proj/
    - __init__.py
    - settings.py
    - urls.py
# proj/proj/celery.py

from __future__ import absolute_import, unicode_literals
import os
from celery import Celery

# set the default Django settings module for the 'celery' program.
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'proj.settings')

app = Celery('proj')

# Using a string here means the worker doesn't have to serialize
# the configuration object to child processes.
# - namespace='CELERY' means all celery-related configuration keys
#   should have a `CELERY_` prefix.
app.config_from_object('django.conf:settings', namespace='CELERY')

# Load task modules from all registered Django app configs.
app.autodiscover_tasks()


@app.task(bind=True)
def debug_task(self):
    print('Request: {0!r}'.format(self.request))

# proj/proj/__init__.py:
from __future__ import absolute_import, unicode_literals

# This will make sure the app is always imported when
# Django starts so that shared_task will use this app.
from .celery import app as celery_app

__all__ = ('celery_app',)

使用 @shared_task 装饰器添加任务


# Create your tasks here
from __future__ import absolute_import, unicode_literals
from celery import shared_task


@shared_task
def add(x, y):
    return x + y


@shared_task
def mul(x, y):
    return x * y


@shared_task
def xsum(numbers):
    return sum(numbers)

在Django中配置Celery

如果要使用Django ORM或Django Cache框架提供results后端,可能需要安装django-celery-results

$ pip install django-celery-results
# proj/proj/settings.py

# 在Django项目的settings.py中将django_celery_results添加到INSTALLED_APPS:
INSTALLED_APPS = (
    ...,
    'django_celery_results',
)

# 配置Celery以使用django-celery-results后端。 假设您使用Django的settings.py来配置Celery,请添加以下设置:
CELERY_RESULT_BACKEND = 'django-db'
# 对于缓存后端,可以使用:
CELERY_CACHE_BACKEND = 'django-cache'
# 通过执行数据库迁移来创建Celery数据库表:
$ python manage.py migrate celery_results

启动Celery worker

# -A 指定celery应用程序所在模块名
$ celery -A proj worker -l info

上面只是举了例子,并没有完整的Celery配置等信息,在Django中使用Celery的一些相关配置详情见 Celery中文文档 - Django

3.2 Flask和Celery

异步发送邮件

# views.py

from flask import Flask
from celery import Celery

app = Flask(__name__)
app.config['CELERY_BROKER_URL'] = 'redis://localhost:6379/0'
app.config['CELERY_RESULT_BACKEND'] = 'redis://localhost:6379/0'

celery = Celery(app.name, broker=app.config['CELERY_BROKER_URL'])
celery.conf.update(app.config)

# Flask-Mail configuration
app.config['MAIL_SERVER'] = 'smtp.googlemail.com'
app.config['MAIL_PORT'] = 587
app.config['MAIL_USE_TLS'] = True
app.config['MAIL_USERNAME'] = os.environ.get('MAIL_USERNAME')
app.config['MAIL_PASSWORD'] = os.environ.get('MAIL_PASSWORD')
app.config['MAIL_DEFAULT_SENDER'] = 'flask@example.com'

@app.route('/', methods=['GET', 'POST'])
def index():
    if request.method == 'GET':
        return render_template('index.html', email=session.get('email', ''))
    email = request.form['email']
    session['email'] = email

    # send the email
    msg = Message('Hello from Flask',
                  recipients=[request.form['email']])
    msg.body = 'This is a test email sent from a background Celery task.'
    if request.form['submit'] == 'Send':
        # send right away
        send_async_email.delay(msg)
        flash('Sending email to {0}'.format(email))
    else:
        # send in one minute
        send_async_email.apply_async(args=[msg], countdown=60)
        flash('An email will be sent to {0} in one minute'.format(email))

    return redirect(url_for('index'))

@celery.task
def send_async_email(msg):
    """Background task to send an email with Flask-Mail."""
    with app.app_context():
        mail.send(msg)

4. 配置Celery

在大型项目中,通常将所有配置集中放到某一个文件中,如celeryconfig.py

# celeryconfig.py

broker_url = "pyamqp://"
result_backend = "rpc://"

task_serializer = "json"
result_serializer = "json"
accept_content = ["json"]
timezone = "Asia/Shanghai"
enable_utc = True        

通过x.config_from_object加载配置

app = Celery('tasks', broker='pyamqp://test:test123456@localhost/myrabbitmq', backend="rpc://")
app.config_from_object('celeryconfig')

通过x.conf.update()更新配置

app = Celery('tasks', broker='pyamqp://test:test123456@localhost/myrabbitmq', backend="rpc://")
app.conf.update(
    task_serializer='json',
    accept_content=['json'],  # Ignore other content
    result_serializer='json',
    timezone='Europe/Oslo',
    enable_utc=True,
)

记录日志

from celery.utils.log import get_task_logger
logger = get_task_logger(__name__)

# TODO
# 然后像使用logging模块中的logger实例一样用就可以了。

任务绑定

通过任务绑定(bind=True),在我们编写的任务函数中可以访问到任务的属性和方法。示例如下:

@app.task(bind=True)
def dump_context(self, x, y):
    print('Executing task id {0.id}, args: {0.args!r} kwargs: {0.kwargs!r}'.format(
            self.request))

5. 总结

Celery其实并不复杂,通过Celery的装饰器将需要异步处理的任务以消息的形式写入消息中间件(如RabbitMQ/Redis中),然后通过启动Celery worker来消费这些消息,并执行这些异步任务,然后将异步任务的执行结果写入到Celery中所配置的结果存储中即可。

6. 参考文章

[1] Celery官方网站
[2] Celery 中文手册
[3] 任务调度利器:Celery
[4] Python 并行分布式框架 Celery 详解
[5] celery 简要概述
[6] python celery 任务队列
[7] 基于 Celery 的后台任务
[8] 在 Flask 中使用 Celery

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值