celery 异步任务小记
这里有一篇写的不错的:http://www.jianshu.com/p/1840035cb510
自己的“格式化”后的内容备忘下:
我们总在说c10k的问题, 也做了不少优化, 然后优化总是不够的。
其中的一个瓶颈就是一些耗时的操作(网络请求/文件操作--含耗时的数据库操作)。
如果我们不关心他们的返回值,则可以将其做成异步任务,保证执行成功即可。
开始阐述之前约定一些概念:
1. web请求处理进程(简称:消息生产者,记做P), 这是我们c10k问题注意的焦点
2. 消息的处理者(简称:消费者,记做C), 在成功“男人”后面默默无闻工作的“女人”
3. 消息存放的地方(简称: 消息队列, 记做Q)
4. 消息/任务, 记做T
基本处理过程:
1. P将T保存到Q
2. C从Q中取出一个T实例, 处理, 若处理失败则将T示例退回到Q(务必保证T得到成功处理)。
最简单的实现方案:
redis 消息队列(利用redis list类型)的lpush/rpop(brpop)来处理。python代码如下:
TaskServer.py
# -*- coding:utf-8 -*-
import traceback
import simplejson
import redis
import uuid
from functools import wraps class TaskExecutor(object):
def __init__(self, task_name , *args, **kwargs):
self.queue = redis.StrictRedis()#host='localhost', port=6378, db=0, password='xxx_tasks')
self.task_name = task_name def _publish_task(self, task_id , func, *args, **kwargs):
self.queue.lpush(self.task_name,
simplejson.dumps({'id':task_id, 'func':func, 'args':args, 'kwargs':kwargs})
) def task(self, func):#decorator
setattr(func,'delay',lambda *args, **kwargs:self._publish_task(uuid.uuid4().hex, func.__name__, *args, **kwargs))
@wraps(func)
def _w(*args, **kwargs):
return func(*args, **kwargs)
return _w def run(self):
print 'waiting for tasks...'
while True:
if self.queue.llen(self.task_name):
msg_data = simplejson.loads( self.queue.rpop(self.task_name))#这里可以用StrictRedis实例的brpop改善,去掉llen轮询。 print 'handling task(id:{0})...'.format(msg_data['id'])
try:
if msg_data.get('func',None):
func = eval(msg_data.get('func'))
if callable(func):
#print msg_data['args'], msg_data['kwargs']
ret = func(*msg_data['args'], **msg_data['kwargs'])
msg_data.update({'result':ret})
self.queue.lpush(self.task_name+'.response.success', simplejson.dumps(msg_data) )
except:
msg_data.update({'failed_times':msg_data.get('failed_times',0)+1, 'failed_reason':traceback.format_exc()})
if msg_data.get('failed_times',0)<10:#最多失败10次,避免死循环
self.queue.rpush(self.task_name,simplejson.dumps(msg_data))
else:
self.queue.lpush(self.task_name+'.response.failure', simplejson.dumps(msg_data) )
print traceback.format_exc() PingTask = TaskExecutor('PingTask') @PingTask.task
def ping_url(url):
import os
os.system('ping -c 2 '+url) if __name__=='__main__':
PingTask.run()
运行服务:python TaskServer.py
ps:
1. TaskExecutor类是一个轻量级的celery.Celery实现。提供了 task修饰器。对被修饰的函数添加delay 方法(将原任务方法名/参数保存到redis的list中--FIFO--实际上celery也是类似的处理)
2. 客户端只要定义自己的TaskExecutor实例以及用此实例的task修饰对应的任务处理函数func。并在代码中待用 func.delay(...)实现异步调用(为了保证成功,最多调用10次); 成功的记录会保存在 redis的 "任务名.response.success" 队列中, 超过10次仍然失败的保存在 “任务名.response.failure"队列中。
3. 待改进的地方是很多的, 比如多线程, 负载均衡。(尚未阅读celery源码)
TaskClient.py
# -*- coding:utf-8 -*-
import sys
sys.path.append('./')
from my_tasks import ping_url
ping_url.delay('www.baidu.com')
ps: 客户端和服务器文件在统一linux目录下。
celery
试验证明, celery目测大体上跟上面的“基本处理过程”基本一致。即:
P将T保存在Q中。
C从Q中取出T处理(保证成功--会不会死循环?执行一个注定失败的任务--就没有验证了)。
celery的运用比较简单:
1.安装celery
2.编写需要异步执行的任务函数,并用celery实例的task修饰器修饰
3.调用异步任务时, 用函数名.delay(参数)形式调用为异步调用。 函数名(参数)方式为同步调用。
4.执行celery监听服务
demo 这里有:http://www.jianshu.com/p/1840035cb510。 再来一个极简的:
tasks.py
# -*- coding:utf-8 -*-
from celery import Celery
brokers = 'redis://127.0.0.1:6379/5'
backend = 'redis://127.0.0.1:6379/6' import time app = Celery('tasks', backend=backend, broker=brokers) @app.task
def add(x,y):
time.sleep(10)
return x+y
运行celery监听服务:celery -A tasks worker -l error
顺便附上测试代码:tasks_test.py(跟tasks.py同一路径,linux环境)
# -*- coding:utf-8 -*-
import sys
sys.path.append('./')
def test():
from tasks import add
for i in range(1000):
add.delay(i,i+1) if __name__=='__main__':
test()
执行之 : python tasks_test.py
(可以1秒内跑完, 证明的确异步处理了)
顺便查看了下进程,发现celery自动开了一个主进程, 与cpu核数相同的子线程。看了下官方文档,有web监控用的插件(flower)。
安装: sudo pip install flower
运行之(跟tasks.py先同目录): celery -A tasks flower --port=5555
效果图如下(木有发现失败任务--"Failed tasks"---很遗憾):

flower的基本原理推测是直接查询Q, 并基于结果输出图表等。
ref: https://abhishek-tiwari.com/post/amqp-rabbitmq-and-celery-a-visual-guide-for-dummies
转载请注明来源:http://www.cnblogs.com/Tommy-Yu/p/5955294.html
谢谢!
celery 异步任务小记的更多相关文章
- Django使用Celery异步任务队列
1 Celery简介 Celery是异步任务队列,可以独立于主进程运行,在主进程退出后,也不影响队列中的任务执行. 任务执行异常退出,重新启动后,会继续执行队列中的其他任务,同时可以缓存停止期间接收 ...
- Celery 异步任务 , 定时任务 , 周期任务 的芹菜
1.什么是Celery?Celery 是芹菜Celery 是基于Python实现的模块, 用于执行异步定时周期任务的其结构的组成是由 1.用户任务 app 2.管道 broker 用于存储 ...
- Django商城项目笔记No.6用户部分-注册接口-短信验证码实现celery异步
Django商城项目笔记No.4用户部分-注册接口-短信验证码实现celery异步 接上一篇,如何解决前后端请求跨域问题? 首先想一下,为什么图片验证码请求的也是后端的api.meiduo.site: ...
- Django --- celery异步任务与RabbitMQ模块
一 RabbitMQ 和 celery 1 celery Celery 是一个 基于python开发的分布式异步消息任务队列,通过它可以轻松的实现任务的异步处理, 如果你的业务场景中需要用到异步任务, ...
- python—Celery异步分布式
python—Celery异步分布式 Celery 是一个python开发的异步分布式任务调度模块,是一个消息传输的中间件,可以理解为一个邮箱,每当应用程序调用celery的异步任务时,会向brok ...
- Celery异步任务重复执行(Redis as broker)
之前讲到利用celery异步处理一些耗时或者耗资源的任务,但是近来分析数据的时候发现一个奇怪的现象,即是某些数据重复了,自然想到是异步任务重复执行了. 查阅之后发现,到如果一个任务太耗时,任务完成时间 ...
- Django之使用celery异步完成发送验证码
使用celery的目的:将项目中耗时的操作放入一个新的进程实现 1.安装celery pip install celery 2.在项目的文件夹下创建包celery_tasks用于保存celery异步任 ...
- celery异步任务、定时任务
阅读目录 一 什么是Celery? 二 Celery的使用场景 三 Celery的安装配置 四 Celery异步任务 五Celery定时任务 六在Django中使用Celery 一 什么是Cele ...
- celery异步发送邮件
利用Django框架发送邮件的详细过程,在前两天的博客中有所记录,但是单纯的那样发邮件是有非常大的问题的,这就需要celery异步发送来解决 首先我们来看一下邮件发送的过程: Django网站先发送到 ...
随机推荐
- DEDE整站动态化或整站静态化设置方法,织梦栏目批量静态/动态方法
跟版网建站接到一个朋友提问,100多各栏目全部要从动态变成静态,里面的文章也要静态化,如何更快捷的设置dede的静态化或者动态化呢? 直接用DEDE后台的SQL命令行工具, SQL语句: DEDE整站 ...
- concat() 方法用于连接两个或多个数组。
我们创建了三个数组,然后使用 concat() 把它们连接起来: <script type="text/javascript"> var arr = new Array ...
- 【ASP.NET实战教程】基于ASP.NET技术下多用户博客系统全程实战开发(NNblog)
岁末主推:牛牛老师主讲,多用户博客系统,基于ASP.NET技术,年后将带来移动业务平台项目项目目标: 打造个性品牌Blogo,定制多用户博客 为每一个博客用户提供个性化的 blogo解决方案,打造精品 ...
- Word2Vec 使用总结
word2vec 是google 推出的做词嵌入(word embedding)的开源工具. 简单的说,它在给定的语料库上训练一个模型,然后会输出所有出现在语料库上的单词的向量表示,这个向量称为&qu ...
- 在Linux中如何使用命令进行RS-232串口通信和数据包解析
文章首发于浩瀚先森博客 1. 获取串口号 在Linux系统中一切皆为文件,所以串口端口号也不例外,都是以设备文件的形式出现.也就是说我们可以用访问文本文件的命令来访问它们. a. 一般串口都是以/de ...
- knockoutJS学习笔记01:从拼接字符串到编写模板引擎
开篇 关于knockout的文章,园里已经有很多大神写过了,而且都写得很好.其实knockout学习起来还是很容易的,看看官网的demo和园里的文章,练习练习就可以上手了(仅限使用,不包含研究源码). ...
- 我也来写:数据库访问类DBHelper
一.前言 相信许多人都百度过:“.net 数据库访问类”.然后就出来一大堆SqlHelper.我也用过这些SqlHelper,也自己写过,一堆静态方法,开始使用起来感觉很不错,它们也确实在很多时候可以 ...
- js实现点击修改按钮之后单元格变成可编辑状态
主要实现原理: 每一行有一个修改按钮 点击修改之后,获取行对象,通过行对象再获取行中单元格数组.然后把每一个单元格中的innerHTML替换成input输入框,并赋值value=原来单元格中的内容,鼠 ...
- 从一个简单的ASP.NET 5站点开启.NET跨平台之旅
在经历了阿里云上“黑色1秒”的空欢喜之后,我们“被迫”考虑实现.NET的跨平台,将Web服务器由Windows换成Linux.而这种“被迫”在一个存在已久的愿望下,变得水到渠成.这个愿望就是 —— “ ...
- 从头写个http client(java)
不熟悉java,但我熟悉http,然后从头打造个简单的httpclient,支持get/post,支持gzip,支持重定向,支持encoding,支持transfer-encoding,支持ssl,支 ...