程序员人生 网站导航

Django中如何使用django-celery完成异步任务

栏目:互联网时间:2015-04-24 07:57:33

本篇博文主要介绍在开发环境中的celery使用,请勿用于部署服务器.

许多Django利用需要履行异步任务, 以便不耽误http request的履行. 我们也能够选择许多方法来完成异步任务, 使用Celery是1个比较好的选择, 由于Celery有着大量的社区支持, 能够完善的扩大, 和Django结合的也很好. Celery不但能在Django中使用, 还能在其他地方被大量的使用. 因此1旦学会使用Celery, 我们可以很方便的在其他项目中使用它.

1. Celery版本

本篇博文主要针对Celery 3.0.x. 初期版本的Celery可能有细微的差别.

2. Celery介绍

Celery的主要用途是履行异步任务, 可以选择延期或定时履行功能. 为何需要履行异步任务呢?

第1, 假定用户正发起1个request, 并等待request完成后返回. 在这1request后面的view功能中, 我们可能需要履行1段花费很长时间的程序任务, 这1时间可能远远大于用户能忍耐的范围. 当这1任务其实不需要立刻履行时, 我们即可以使用Celery在后台履行, 而不影响用户阅读网页. 当有任务需要访问远程服务器完成时, 我们常常都没法肯定需要花费的时间.

第2则是定期履行某些任务. 比如每小时需要检查1下天气预报, 然后将数据贮存到数据库中. 我们可以编写这1任务, 然后让Celery每小时履行1次. 这样我们的web利用便能获得最新的天气预报信息.

我们这里所讲的任务task, 就是1个Python功能(function). 定期履行1个任务可以被认为是延时履行该功能. 我们可使用Celery延迟5分钟调用function task1, 并传入参数(1, 2, 3). 或我们也能够每天午夜运行该function.

我们偏向于将Celery放入项目中, 便于task访问统1数据库和Django设置.

当task准备运行时, Celery会将其放入列队queue中. queue中贮存着可以运行的task的list. 我们可使用多个queue, 但为了简单, 这里我们只使用1个.

将任务task放入queue就像加入todo list1样. 为了使task运行, 我们还需要在其他线程中运行的苦工worker. worker实时视察着代运行的task, 并逐1运行这些task. 你可使用多个worker, 通常他们位于不同服务器上. 一样为了简单起见, 我们这只是用1个worker.

我们稍后会讨论queue, worker和另外1个10分重要的进程, 接下来我们来动动手:

3. 安装Celery

我们可使用pip在vietualenv中安装:

pip install django-celery

4. Django设置

我们暂时使用django runserver来启动celery. 而Celery代理人(broker), 我们使用Django database broker implementation. 现在我们只需要知道Celery需要broker, 使用django本身即可以充当broker. (但在部署时, 我们最好使用更稳定和高效的broker, 例如Redis.)

在settings.py中:

import djcelery djcelery.setup_loader() BROKER_URL = 'django://' ... INSTALLED_APPS = ( ... 'djcelery', 'kombu.transport.django', ... )

第12项是必须的, 第3项则告知Celery使用Django项目作为broker.

在INSTALLED_APPS中添加的djcelery是必须的. kombu.transport.django则是基于Django的broker

最后创建Celery所需的数据表, 如果使用South作为数据迁移工具, 则运行:

python manage.py migrate

否则运行: (Django 1.6或Django 1.7都可以)

python manage.py syncdb

5. 创建1个task

正如前面所说的, 1个task就是1个Pyhton function. 但Celery需要知道这1function是task, 因此我们可使用celery自带的装潢器decorator: @task. 在django app目录中创建taske.py:

from celery import task @task() def add(x, y): return x + y

当settings.py中的djcelery.setup_loader()运行时, Celery便会查看所有INSTALLED_APPS中app目录中的tasks.py文件, 找到标记为task的function, 并将它们注册为celery task.

将function标注为task其实不会妨碍他们的正常履行. 你还是可以像平时那样调用它: z = add(1, 2).

6. 履行task

让我们以1个简单的例子作为开始. 例如我们希望在用户发出request后异步履行该task, 马上返回response, 从而不阻塞该request, 使用户有1个流畅的访问进程. 那末, 我们可使用.delay, 例如在在views.py的1个view中:

from myapp.tasks import add ... add.delay(2, 2) ...

Celery会将task加入到queue中, 并马上返回. 而在1旁待命的worker看到该task后, 便会依照设定履行它, 并将他从queue中移除. 而worker则会履行以下代码:

import myapp.tasks.add myapp.tasks.add(2, 2)

7. 关于import

这里需要注意的是, 在impprt task时, 需要保持1致. 由于在履行djcelery.setup_loader()时, task是以INSTALLED_APPS中的app名, 加.tasks.function_name注册的, 如果我们由于python path不同而使用不同的援用方式时(例如在tasks.py中使用from myproject.myapp.tasks import add情势), Celery将没法得知这是同1task, 因此可能会引发奇怪的bug.

8. 测试

a. 启动worker

正如之前说到的, 我们需要worker来履行task. 以下是在开发环境中的如何启动worker:

首先启动terminal, 犹如开发django项目1样, 激活virtualenv, 切换到django项目目录. 然后启动django自带web服务器: python manage.py runserver.

然后启动worker:

如果用gevent需要加参数-P gevent

python manage.py celery worker --loglevel=info

此时, worker将会在该terminal中运行, 并显示输出结果.

b. 启动task

打开新的terminal, 激活virtualenv, 并切换到django项目目录:

$ python manage.py shell >>> from myapp.tasks import add >>> add.delay(2, 2)

此时, 你可以在worker窗口中看到worker履行该task:

[2014-10-07 08:47:08,076: INFO/MainProcess] Got task from broker: myapp.tasks.add[e080e047-b2a2-43a7-af74-d7d9d98b02fc]
------分隔线----------------------------
------分隔线----------------------------

最新技术推荐