【Python之路】特别篇--Celery
Celery介绍和基本使用
Celery 是一个分布式异步消息队列,通过它可以轻松的实现任务的异步处理
举几个实例场景中可用的例子:
你想对100台机器执行一条批量命令,可能会花很长时间 ,但你不想让你的程序等着结果返回,而是给你返回 一个任务ID,你过一段时间只需要拿着这个任务id就可以拿到任务执行结果, 在任务执行ing进行时,你可以继续做其它的事情。
你想做一个定时任务,比如每天检测一下你们所有客户的资料,如果发现今天 是客户的生日,就给他发个短信祝福
Celery 在执行任务时需要通过一个消息中间件来接收和发送任务消息,以及存储任务结果, 一般使用rabbitMQ or Redis
Celery有以下优点:
简单:一单熟悉了celery的工作流程后,配置和使用还是比较简单的
高可用:当任务执行失败或执行过程中发生连接中断,celery 会自动尝试重新执行任务
快速:一个单进程的celery每分钟可处理上百万个任务
灵活: 几乎celery的各个组件都可以被扩展及自定制
Celery基本工作流程图:
Celery安装使用
1、Celery的默认broker是RabbitMQ, 仅需配置一行就可以
- broker_url = 'amqp://my_user:my_password@localhost:5672//'
2、Redis做broker
- broker_url = 'redis://localhost:6379'
- broker_url = 'redis://:my_password@localhost:port'
如果想获取每个任务的执行结果,还需要配置一下把任务结果存在哪
- result_backend = 'redis://localhost:6379'
一、创建一个celery application 用来定义你的任务列表
①.创建一个任务 tasks.py
- from celery import Celery
- app = Celery('celery_test',
- broker='redis://localhost',
- backend='redis://localhost')
- @app.task
- def add(x,y):
- print("running...",x,y)
- return x+y
②.启动Celery Worker来开始监听并执行任务
- $ celery -A tasks worker --loglevel=info [debug] # tasks 为 tasks文件路径!
- $ celery -A tasks worker -l info
③.调用任务
- >>> from tasks import add
- >>> add.delay(4, 4)
worker终端会显示收到 一个任务,此时你想看任务结果的话,需要在调用 任务时 赋值个变量
- >>> result = add.delay(4, 4)
- >>> result.ready() # 返回执行状态
- >>> result.get(timeout=1) # 超时报错
- >>> result.get(propagate=False) # 程序执行过程出错报异常
- >>> result.traceback # 获取异常信息
注:任务结果需要是可以json转化的,celery代码修改后,worker需要重启
二、在项目中使用celery
可以把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://192.168.18.147',
- backend = 'redis://192.168.18.147',
- include=['my_proj.tasks'])
- # Optional configuration, see the application user guide.
- app.conf.update(
- result_expires=3600,
- )
- if __name__ == '__main__':
- app.start()
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)
启动worker 方式一
- $ celery -A proj worker -l info
启动worker 方式二 后台启动
- celery multi start w1 -A proj -l info # w1 自定义名字
- celery multi restart w1 -A proj -l info
- celery multi stop w1 -A proj -l info
三、Celery 定时任务
celery支持定时任务,设定好任务的执行时间,celery就会定时自动帮你执行, 这个定时任务模块叫celery beat
periodic_task.py
- 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执行的任务
- 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
- $ celery -A periodic_task beat
启动celery worker来执行任务
- $ celery -A periodic_task worker
更复杂的定时配置
- 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任务
还有更多定时配置方式如下:
Example | Meaning |
crontab() | Execute every minute. |
crontab(minute=0, hour=0) | Execute daily at midnight. |
crontab(minute=0, hour='*/3') | Execute every three hours: midnight, 3am, 6am, 9am, noon, 3pm, 6pm, 9pm. |
|
Same as previous. |
crontab(minute='*/15') | Execute every 15 minutes. |
crontab(day_of_week='sunday') | Execute every minute (!) at Sundays. |
|
Same as previous. |
|
Execute every ten minutes, but only between 3-4 am, 5-6 pm, and 10-11 pm on Thursdays or Fridays. |
crontab(minute=0,hour='*/2,*/3') | Execute every even hour, and every hour divisible by three. This means: at every hour except: 1am, 5am, 7am, 11am, 1pm, 5pm, 7pm, 11pm |
crontab(minute=0, hour='*/5') | Execute hour divisible by 5. This means that it is triggered at 3pm, not 5pm (since 3pm equals the 24-hour clock value of “15”, which is divisible by 5). |
crontab(minute=0, hour='*/3,8-17') | Execute every hour divisible by 3, and every hour during office hours (8am-5pm). |
crontab(0, 0,day_of_month='2') | Execute on the second day of every month. |
|
Execute on every even numbered day. |
|
Execute on the first and third weeks of the month. |
|
Execute on the eleventh of May every year. |
crontab(0, 0,month_of_year='*/3') | Execute on the first month of every quarter. |
上面能满足你绝大多数定时任务需求了,甚至还能根据潮起潮落来配置定时任务,
具体看 http://docs.celeryproject.org/en/latest/userguide/periodic-tasks.html#solar-schedules
四、Django项目中使用celery
目录格式:
- CeleryTest/
- CeleryTest/__init__.py
- /celery.py
- /setting.py
- app/task.py
- ....
- /views.py
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', 'CeleryTest.settings')
- app = Celery('CeleryTest')
- # Using a string here means the worker don'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))
__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']
setting.py内容
- CELERY_BROKER_URL = 'redis://192.168.18.147'
- CELERY_RESULT_BACKEND = 'redis://192.168.18.147'
tasks.py内容 (必须在各app根目录下,不能随意命名)
- 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)
views.py调用celery tasks
- from app01 import tasks
- from celery.result import AsyncResult
- def index(request):
- res = tasks.add.delay(9,8)
- print("start running task")
- return HttpResponse(res.task_id)
- def get_data(request,task_id):
- result = AsyncResult(task_id)
- return HttpResponse(result.status)
AsyncResult 根据返回的id获取结果
调用worker
- $:~/..../CeleryTest$ celery -A CeleryTest worker -l info
五、django中使用计划任务功能
1.安装package
- $ pip install django-celery-beat
2.setting中注册app
- INSTALLED_APPS = (
- ...,
- 'django_celery_beat',
- )
3.生成数据库表
- $ python manage.py migrate
4. Django-Admin 创建任务
5.开启任务调度器
- $ celery -A proj beat -l info -S django
在admin页面里,有3张表
配置完长这样
此时启动你的celery beat 和worker,会发现每隔2分钟,beat会发起一个任务消息让worker执行scp_task任务
注意,经测试,每添加或修改一个任务,celery beat都需要重启一次,要不然新的配置不会被celery beat进程读到
【Python之路】特别篇--Celery的更多相关文章
- python之路基础篇
基础篇 1.Python基础之初识python 2.Python数据类型之字符串 3.Python数据类型之列表 4.Python数据类型之元祖 5.Python数据类型之字典 6.Python Se ...
- python之路入门篇
一. Python介绍 python的创始人为吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,Guido开始写能够解释Python语言语法的解释器.Python这个名字,来 ...
- python之路——基础篇(2)模块
模块:os.sys.time.logging.json/pickle.hashlib.random.re 模块分为三种: 自定义模块 第三方模块 内置模块 自定义模块 1.定义模块 将一系列功能函数或 ...
- python之路第一篇
一.python环境的搭建 1.window下环境的搭建 (1).在 https://www.python.org/downloads/ 下载自己系统所需要的python版本 (2).安装python ...
- python之路第二篇(基础篇)
入门知识: 一.关于作用域: 对于变量的作用域,执行声明并在内存中存在,该变量就可以在下面的代码中使用. if 10 == 10: name = 'allen' print name 以下结论对吗? ...
- Python之路(第九篇)Python文件操作
一.文件的操作 文件句柄 = open('文件路径+文件名', '模式') 例子 f = open("test.txt","r",encoding = “utf ...
- Python之路(第二篇):Python基本数据类型字符串(一)
一.基础 1.编码 UTF-8:中文占3个字节 GBK:中文占2个字节 Unicode.UTF-8.GBK三者关系 ascii码是只能表示英文字符,用8个字节表示英文,unicode是统一码,世界通用 ...
- Python之路(第一篇):Python简介和基础
一.开发简介 1.开发: 开发语言: 高级语言:python.JAVA.PHP.C#..ruby.Go-->字节码 低级语言: ...
- Python之路(第四十一篇)线程概念、线程背景、线程特点、threading模块、开启线程的方式
一.线程 之前我们已经了解了操作系统中进程的概念,程序并不能单独运行,只有将程序装载到内存中,系统为它分配资源才能运行,而这种执行的程序就称之为进程.程序和进程的区别就在于:程序是指令的集合,它是 ...
随机推荐
- 石子合并2——区间DP【洛谷P1880题解】
[区间dp让人头痛……还是要多写些题目练手,抽空写篇博客总结一下] 这题区间dp入门题,理解区间dp或者练手都很妙 ——题目链接—— (或者直接看下面) 题面 在一个圆形操场的四周摆放N堆石子,现要将 ...
- Treasure Island(两遍dfs)-- Codeforces Round #583 (Div. 1 + Div. 2, based on Olympiad of Metropolises)
题意:https://codeforc.es/contest/1214/problem/D 给你一个n*m的图,每次可以往右或者往下走,问你使(1,1)不能到(n,m)最少要放多少 ‘ # ’ . 思 ...
- DRF 序列化组件 序列化的两种方式 反序列化 反序列化的校验
序列化组件 django自带的有序列化组件不过不可控不建议使用(了解) from django.core import serializers class Books(APIView): def ge ...
- Spring 容器中 Bean 的生命周期
Spring 容器中 Bean 的生命周期 1. init-method 和 destory-method 方法 Spring 初始化 bean 或销毁 bean 时,有时需要作一些处理工作,因此 s ...
- 树莓派安装SSH
1. 安装ssh sudo apt-get install openssh-server 2. 检查树莓派SSH服务是否开启 ps -e|grep ssh 3. SSH服务开启 sudo /etc/i ...
- -bash: fork: retry: 没有子进程
今天遇到一个问题 -bash: fork: retry: 没有子进程 解决方法 设置各linux 用户的最大进程数,下面我把某linux用户的最大进程数设为10000个: ulimit -u 10 ...
- C#面向对象15 多态
多态 概念:让一个对象能够表现出多种的状态(类型) 实现多态的3种手段:1.虚方法 2.抽象类 3.接口 1.虚方法 步骤:1.将父类的方法标记为虚方法,使用关键字 virtual,这个函数可以被子类 ...
- Winfrom 定时锁屏
#region 锁屏 public struct LASTINPUTINFO { [MarshalAs(UnmanagedType.U4)] public int cbSize; [MarshalAs ...
- 抓包工具之tcpdump
tcpdump 官网 -> http://www.tcpdump.org 1. 安装步骤 在官网分别下载 Tcpdump.Libpcap 这两个包链接 在安装Tcpdump之前,先安装Libpc ...
- 完美解决Uncaught SyntaxError: Unexpected end of input
Unexpected end of input 的英文意思是“意外的终止输入” 他通常表示我们浏览器在读取我们的js代码时,碰到了不可预知的错误,导致浏览器 无语进行下面的读取 通常造成这种错误的原 ...