Celery的介绍
1、Celery的简介以及基本使用
Celery 是一个 基于python开发的分布式异步消息任务队列,通过它可以轻松的实现任务的异步处理, 如果你的业务场景中需要用到异步任务,就可以考虑使用celery, 举几个实例场景中可用 的例子:
- 你想对100台机器执行一条批量命令,可能会花很长时间 ,但你不想让你的程序等着结果返回,而是给你返回 一个任务ID,你过一段时间只需要拿着这个任务id就可以拿到任务执行结果, 在任务执行ing进行时,你可以继续做其它的事情。
- 你想做一个定时任务,比如每天检测一下你们所有客户的资料,如果发现今天 是客户的生日,就给他发个短信祝福
Celery 在执行任务时需要通过一个消息中间件来接收和发送任务消息,以及存储任务结果, 一般使用rabbitMQ or Redis,后面会讲
1.1 Celery有以下优点:
- 简单:一单熟悉了celery的工作流程后,配置和使用还是比较简单的
- 高可用:当任务执行失败或执行过程中发生连接中断,celery 会自动尝试重新执行任务
- 快速:一个单进程的celery每分钟可处理上百万个任务
- 灵活: 几乎celery的各个组件都可以被扩展及自定制
Celery基本工作流程图
Celery安装使用
Celery的默认broker是RabbitMQ, 仅需配置一行就可以
1 | broker_url = 'amqp://guest:guest@localhost:5672//' |
rabbitMQ 没装的话请装一下,安装看这里 http://docs.celeryproject.org/en/latest/getting-started/brokers/rabbitmq.html#id3
使用Redis做broker也可以
安装celery模块
1 | pip3 install celery |
创建一个celery application 用来定义你的任务列表
创建一个任务文件就叫tasks.py吧
1 2 3 4 5 6 7 8 9 10 11 | from celery import Celery app = Celery( 'tasks' , broker = 'redis://localhost' , # broker='redis://:123123@106.13.104.194:6379', backend = 'redis://localhost' ) @app .task def add(x,y): print ( "running..." ,x,y) return x + y |
启动Celery Worker来开始监听并执行任务
1 | celery - A tasks worker - - loglevel = info |
启动Celery报错问题的处理:
1 2 3 4 5 6 7 8 9 10 11 12 13 | File "/usr/local/python3/lib/python3.7/site-packages/celery/backends/redis.py" , line 22 from . import async, base ^ SyntaxError: invalid syntax 搜索了一下错误原因,原来是async名称更换了,如下 [Rename `async` to `asynchronous` (async is a reserved keyword in Python 3.7 ) #4879](https://github.com/celery/celery/pull/4879) 开发人员已经处理了这个issue,合并了master,快速的解决方案是通过github安装celery,命令如下: pip3 install - - upgrade https: / / github.com / celery / celery / tarball / master 再次运次,那个应该可以看到如下正常输出: |
调用任务
再打开一个终端, 进行命令行模式,调用任务
1 2 | from tasks import add add.delay( 4 , 4 ) |
看你的worker终端会显示收到 一个任务,此时你想看任务结果的话,需要在调用 任务时 赋值个变量
1 | result = add.delay( 4 , 4 ) |
1 2 3 | result.get(timeout = 1 ) result.ready() result.get(propagate = False ) |
2、在项目中如何使用celery
可以把celery配置成一个应用
目录格式如下
1 2 3 | proj / __init__.py / celery.py / tasks.py |
proj/celery.py内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | from __future__ import absolute_import, unicode_literals from celery import Celery app = Celery( 'proj' , broker = 'redis://:123123@106.13.104.194:6379' , backend = 'redis://:123123@106.13.104.194:6379' , include = [ 'proj.tasks' ]) # Optional configuration, see the application user guide. app.conf.update( result_expires = 3600 , ) if __name__ = = '__main__' : app.start() |
关于redis连接配置
1 2 3 4 5 6 7 | Configuration is easy, just configure the location of your Redis database: app.conf.broker_url = 'redis://localhost:6379/0' Where the URL is in the format of:【如果中间件有认证操作】 redis: / / :password@hostname:port / db_number all fields after the scheme are optional, and will default to localhost on port 6379 , using database 0. 如果想获取每个任务的执行结果,还需要配置一下把任务结果存在哪 If you also want to store the state and return values of tasks in Redis, you should configure these settings: app.conf.result_backend = 'redis://localhost:6379/0' |
proj/tasks.py中的内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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) |
启动worker
1 | celery - A proj worker - l info |
运行celery任务
后台启动worker
1 | celery multi start w1 - A proj - l info |
三、Celery 定时任务
celery支持定时任务,设定好任务的执行时间,celery就会定时自动帮你执行, 这个定时任务模块叫celery beat
写一个脚本 叫periodic_task.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | from celery import Celery from celery.schedules import crontab app = Celery() @app .on_after_configure.connect def setup_periodic_tasks(sender, * * kwargs): # Calls test('hello') every 10 seconds. sender.add_periodic_task( 10.0 , test.s( 'hello' ), name = 'add every 10' ) # Calls test('world') every 30 seconds sender.add_periodic_task( 30.0 , test.s( 'world' ), expires = 10 ) # Executes every Monday morning at 7:30 a.m. sender.add_periodic_task( crontab(hour = 7 , minute = 30 , day_of_week = 1 ), test.s( 'Happy Mondays!' ), ) @app .task def test(arg): print (arg) |
add_periodic_task 会添加一条定时任务
上面是通过调用函数添加定时任务,也可以像写配置文件 一样的形式添加, 下面是每30s执行的任务
1 2 3 4 5 6 7 8 | app.conf.beat_schedule = { 'add-every-30-seconds' : { 'task' : 'tasks.add' , 'schedule' : 30.0 , 'args' : ( 16 , 16 ) }, } app.conf.timezone = 'UTC' |
任务添加好了,需要让celery单独启动一个进程来定时发起这些任务, 注意, 这里是发起任务,不是执行,这个进程只会不断的去检查你的任务计划, 每发现有任务需要执行了,就发起一个任务调用消息,交给celery worker去执行
启动任务调度器 celery beat
1 | celery - A periodic_task beat |
输出like below
1 2 3 4 5 6 7 8 9 10 | celery beat v4. 0.2 (latentcall) is starting. __ - ... __ - _ LocalTime - > 2017 - 02 - 08 18 : 39 : 31 Configuration - > . broker - > redis: / / localhost: 6379 / / . loader - > celery.loaders.app.AppLoader . scheduler - > celery.beat.PersistentScheduler . db - > celerybeat - schedule . logfile - > [stderr]@ % WARNING . maxinterval - > 5.00 minutes ( 300s ) |
此时还差一步,就是还需要启动一个worker,负责执行celery beat发起的任务
启动celery worker来执行任务
1 | celery - A periodic_task worker |
好啦,此时观察worker的输出,是不是每隔一小会,就会执行一次定时任务呢!
更复杂的定时配置
上面的定时任务比较简单,只是每多少s执行一个任务,但如果你想要每周一三五的早上8点给你发邮件怎么办呢?哈,其实也简单,用crontab功能,跟linux自带的crontab功能是一样的,可以个性化定制任务执行时间
1 2 3 4 5 6 7 8 9 10 | from celery.schedules import crontab app.conf.beat_schedule = { # Executes every Monday morning at 7:30 a.m. 'add-every-monday-morning' : { 'task' : 'tasks.add' , 'schedule' : crontab(hour = 7 , minute = 30 , day_of_week = 1 ), 'args' : ( 16 , 16 ), }, } |
上面的这条意思是每周1的早上7.30执行tasks.add任务
四、最佳实践之与django结合
django+celery项目结构
django 可以轻松跟celery结合实现异步任务,只需简单配置即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | - project_name - app01 - __init__.py - admin.py - views.py - modes.py - tasks.py #celery用来执行任务的文件,task里的任务由views函数里去触发 - urls.py - views.py - project_name - __init__.py #初始化celery - celery.py #celery 定义实例 - settings.py #用来配置redis或rabbitmq地址 - urls.py - views.py - wsgi.py - templates - static - manager.py - db.sqlite3 |
celery.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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' , 'project_name.settings' ) #这里要写项目名称 app = Celery( 'project_name' ) app.config_from_object( 'django.conf:settings' , namespace = 'CELERY' ) #这里配置settings里与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)) |
project_name/__init__.py
1 2 3 4 5 6 7 8 9 | 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' ] |
tasks.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #!/usr/bin/env python #-*-coding:utf-8-*- from __future__ import absolute_import, unicode_literals from celery import shared_task import subprocess @shared_task def add(x, y): return x + y @shared_task def mul(x, y): return x * y @shared_task def cmd_run(cmd): result = subprocess.Popen(cmd,shell = True ,stdout = subprocess.PIPE,stderr = subprocess.PIPE) return result.stdout.read().decode( "utf-8" ) |
app01/views.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | from django.shortcuts import render,redirect,HttpResponse from django_celery import tasks #引入task from celery.result import AsyncResult def test_celery(request): #这里用来触发tasks里的任务 res = tasks.cmd_run.delay( "ipconfig" , ) #print (res.get) #如果在此处直接get会变成同步 return HttpResponse(res.task_id) #获取taskid #获取任务执行状态返回给前端 def task_res(request): result = AsyncResult( id = task_id) return HttpResponse(result.status) |
app01/urls.py
1 2 3 4 5 6 7 8 | from django.conf.urls import url,include from django.contrib import admin from django_celery import views urlpatterns = [ url(r '^admin/' , admin.site.urls), url(r '^test_celery/$' ,views.test_celery) ] |
django&celery 定时任务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | pip3 install django - celery - beat ##settings.py 里注册 django-celery-beat INSTALLED_APPS = [ 'django_celery_beat' , ] python manage.py migrate D:\django - project\wechat>python manage.py migrate Operations to perform: Apply all migrations: auth, sessions, django_celery_beat, contenttypes, admin Running migrations: Rendering model states... DONE Applying contenttypes. 0001_initial ... OK Applying auth. 0001_initial ... OK Applying admin. 0001_initial ... OK Applying admin. 0002_logentry_remove_auto_add ... OK Applying contenttypes. 0002_remove_content_type_name ... OK Applying auth. 0002_alter_permission_name_max_length ... OK Applying auth. 0003_alter_user_email_max_length ... OK Applying auth. 0004_alter_user_username_opts ... OK Applying auth. 0005_alter_user_last_login_null ... OK Applying auth. 0006_require_contenttypes_0002 ... OK Applying auth. 0007_alter_validators_add_error_messages ... OK Applying django_celery_beat. 0001_initial ... OK Applying django_celery_beat. 0002_auto_20161118_0346 ... OK Applying django_celery_beat. 0003_auto_20161209_0049 ... OK Applying django_celery_beat. 0004_auto_20170221_0000 ... OK Applying django_celery_beat. 0005_add_solarschedule_events_choices ... OK Applying django_celery_beat. 0006_auto_20180210_1226 ... OK Applying sessions. 0001_initial ... OK |
To install and use this extension:
-
Use pip to install the package:
$ pip install django-celery-beat
-
Add the
django_celery_beat
module toINSTALLED_APPS
in your Django project’settings.py
:INSTALLED_APPS = ( ..., 'django_celery_beat', ) Note that there is no dash in the module name, only underscores.
-
Apply Django database migrations so that the necessary tables are created:
$ python manage.py migrate
-
Start the celery beat service using the
django
scheduler:$ celery -A proj beat -l info -S django
-
Visit the Django-Admin interface to set up some periodic tasks.
在admin页面里,有3张表
配置完长这样
此时启动你的celery beat 和worker,会发现每隔2分钟,beat会发起一个任务消息让worker执行scp_task任务
注意,经测试,每添加或修改一个任务,celery beat都需要重启一次,要不然新的配置不会被celery beat进程读到
参考:https://www.cnblogs.com/alex3714/articles/6351797.html
I can feel you forgetting me。。 有一种默契叫做我不理你,你就不理我
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通