Python使用Redis实现作业调度系统(超简单)


Posted in Python onMarch 22, 2016

概述

Redis是一个开源,先进的key-value存储,并用于构建高性能,可扩展的Web应用程序的完美解决方案。

Redis从它的许多竞争继承来的三个主要特点:

Redis数据库完全在内存中,使用磁盘仅用于持久性。

相比许多键值数据存储,Redis拥有一套较为丰富的数据类型。

Redis可以将数据复制到任意数量的从服务器。

Redis 优势

异常快速:Redis的速度非常快,每秒能执行约11万集合,每秒约81000+条记录。

支持丰富的数据类型:Redis支持最大多数开发人员已经知道像列表,集合,有序集合,散列数据类型。这使得它非常容易解决各种各样的问题,因为我们知道哪些问题是可以处理通过它的数据类型更好。

操作都是原子性:所有Redis操作是原子的,这保证了如果两个客户端同时访问的Redis服务器将获得更新后的值。

多功能实用工具:Redis是一个多实用的工具,可以在多个用例如缓存,消息,队列使用(Redis原生支持发布/订阅),任何短暂的数据,应用程序,如Web应用程序会话,网页命中计数等。

步入主题:

Redis作为内存数据库的一个典型代表,已经在很多应用场景中被使用,这里仅就Redis的pub/sub功能来说说怎样通过此功能来实现一个简单的作业调度系统。这里只是想展现一个简单的想法,所以还是有很多需要考虑的东西没有包括在这个例子中,比如错误处理,持久化等。

下面是实现上的想法

MyMaster:集群的master节点程序,负责产生作业,派发作业和获取执行结果。

MySlave:集群的计算节点程序,每个计算节点一个,负责获取作业并运行,并将结果发送会master节点。

channel CHANNEL_DISPATCH:每个slave节点订阅一个channel,比如“CHANNEL_DISPATCH_[idx或机器名]”,master会向此channel中publish被dispatch的作业。

channel CHANNEL_RESULT:用来保存作业结果的channel,master和slave共享此channel,master订阅此channel来获取作业运行结果,每个slave负责将作业执行结果发布到此channel中。

Master代码

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import time
import threading
import random
import redis
REDIS_HOST = 'localhost'
REDIS_PORT = 6379
REDIS_DB = 0
CHANNEL_DISPATCH = 'CHANNEL_DISPATCH'
CHANNEL_RESULT = 'CHANNEL_RESULT'
class MyMaster():
def __init__(self):
pass
def start(self):
MyServerResultHandleThread().start()
MyServerDispatchThread().start()
class MyServerDispatchThread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
r = redis.StrictRedis(host=REDIS_HOST, port=REDIS_PORT, db=REDIS_DB)
for i in range(1, 100):
channel = CHANNEL_DISPATCH + '_' + str(random.randint(1, 3))
print("Dispatch job %s to %s" % (str(i), channel))
ret = r.publish(channel, str(i))
if ret == 0:
print("Dispatch job %s failed." % str(i))
time.sleep(5)
class MyServerResultHandleThread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
r = redis.StrictRedis(host=REDIS_HOST, port=REDIS_PORT, db=REDIS_DB)
p = r.pubsub()
p.subscribe(CHANNEL_RESULT)
for message in p.listen():
if message['type'] != 'message':
continue
print("Received finished job %s" % message['data'])
if __name__ == "__main__":
MyMaster().start()
time.sleep(10000)

说明

MyMaster类 - master主程序,用来启动dispatch和resulthandler的线程

MyServerDispatchThread类 - 派发作业线程,产生作业并派发到计算节点

MyServerResultHandleThread类 - 作业运行结果处理线程,从channel里获取作业结果并显示

Slave代码

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from datetime import datetime
import time
import threading
import random
import redis
REDIS_HOST = 'localhost'
REDIS_PORT = 6379
REDIS_DB = 0
CHANNEL_DISPATCH = 'CHANNEL_DISPATCH'
CHANNEL_RESULT = 'CHANNEL_RESULT'
class MySlave():
def __init__(self):
pass
def start(self):
for i in range(1, 4):
MyJobWorkerThread(CHANNEL_DISPATCH + '_' + str(i)).start()
class MyJobWorkerThread(threading.Thread):
def __init__(self, channel):
threading.Thread.__init__(self)
self.channel = channel
def run(self):
r = redis.StrictRedis(host=REDIS_HOST, port=REDIS_PORT, db=REDIS_DB)
p = r.pubsub()
p.subscribe(self.channel)
for message in p.listen():
if message['type'] != 'message':
continue
print("%s: Received dispatched job %s " % (self.channel, message['data']))
print("%s: Run dispatched job %s " % (self.channel, message['data']))
time.sleep(2)
print("%s: Send finished job %s " % (self.channel, message['data']))
ret = r.publish(CHANNEL_RESULT, message['data'])
if ret == 0:
print("%s: Send finished job %s failed." % (self.channel, message['data']))
if __name__ == "__main__":
MySlave().start()
time.sleep(10000)

说明

MySlave类 - slave节点主程序,用来启动MyJobWorkerThread的线程

MyJobWorkerThread类 - 从channel里获取派发的作业并将运行结果发送回master

测试

首先运行MySlave来定义派发作业channel。

然后运行MyMaster派发作业并显示执行结果。

有关Python使用Redis实现作业调度系统(超简单),小编就给大家介绍这么多,希望对大家有所帮助!

Python 相关文章推荐
Python set集合类型操作总结
Nov 07 Python
python根据出生日期获得年龄的方法
Mar 31 Python
Python中将字典转换为XML以及相关的命名空间解析
Oct 15 Python
Python2.x与Python3.x的区别
Jan 14 Python
玩转python selenium鼠标键盘操作(ActionChains)
Apr 12 Python
Python 编码规范(Google Python Style Guide)
May 05 Python
Python中super函数用法实例分析
Mar 18 Python
Python 编程速成(推荐)
Apr 15 Python
python3反转字符串的3种方法(小结)
Nov 07 Python
python语言线程标准库threading.local解读总结
Nov 10 Python
详解Django中views数据查询使用locals()函数进行优化
Aug 24 Python
浅析Python中字符串的intern机制
Oct 03 Python
python编写简单爬虫资料汇总
Mar 22 #Python
使用Nginx+uWsgi实现Python的Django框架站点动静分离
Mar 21 #Python
Python中的条件判断语句与循环语句用法小结
Mar 21 #Python
举例讲解Python中的迭代器、生成器与列表解析用法
Mar 20 #Python
深入解析Python中函数的参数与作用域
Mar 20 #Python
总结Python编程中函数的使用要点
Mar 20 #Python
两个命令把 Vim 打造成 Python IDE的方法
Mar 20 #Python
You might like
PHP实现对二维数组某个键排序的方法
2016/09/14 PHP
PHP不使用内置函数实现字符串转整型的方法示例
2017/07/03 PHP
laravel手动创建数组分页的实现代码
2018/06/07 PHP
PHP实现统计代码行数小工具
2019/09/19 PHP
用 Javascript 验证表单(form)中多选框(checkbox)值
2009/09/08 Javascript
Colortip基于jquery的信息提示框插件在IE6下面的显示问题修正方法
2010/12/06 Javascript
在jquery中处理带有命名空间的XML数据
2011/06/13 Javascript
IE6、IE7中获取Button元素的值的bug说明
2011/08/28 Javascript
js 获取计算后的样式写法及注意事项
2013/02/25 Javascript
用JavaScript获取DOM元素位置和尺寸大小的方法
2013/04/12 Javascript
JavaScript对内存分配及管理机制详细解析
2013/11/11 Javascript
js中函数调用的两种常用方法使用介绍
2014/07/17 Javascript
JavaScript字符串对象charAt方法入门实例(用于取得指定位置的字符)
2014/10/17 Javascript
jQuery右侧选项卡焦点图片轮播特效代码分享
2015/09/05 Javascript
微信小程序 缓存(本地缓存、异步缓存、同步缓存)详解
2017/01/17 Javascript
微信小程序实现锚点定位楼层跳跃的实例
2017/05/18 Javascript
微信小程序日历组件calendar详解及实例
2017/06/08 Javascript
AngularJS中使用three.js的实例详解
2017/07/21 Javascript
解决koa2 ctx.render is not a function报错问题
2018/08/07 Javascript
[50:27]Secret vs VG 2018国际邀请赛小组赛BO2 第二场 8.17
2018/08/20 DOTA
[43:57]Liquid vs Mineski 2019国际邀请赛小组赛 BO2 第二场 8.16
2019/08/19 DOTA
python设置检查点简单实现代码
2014/07/01 Python
Python中http请求方法库汇总
2016/01/06 Python
Python切片操作深入详解
2018/07/27 Python
python 利用文件锁单例执行脚本的方法
2019/02/19 Python
python基于SMTP协议发送邮件
2019/05/31 Python
pycharm中使用request和Pytest进行接口测试的方法
2020/07/31 Python
python定时截屏实现
2020/11/02 Python
CSS3教程(4):网页边框和网页文字阴影
2009/04/02 HTML / CSS
css3与html5实现响应式导航菜单(导航栏)效果分享
2014/02/12 HTML / CSS
实习单位接收函模板
2014/01/10 职场文书
主管会计岗位职责
2014/03/13 职场文书
金融与证券专业求职信
2014/06/22 职场文书
Python操作CSV格式文件的方法大全
2021/07/15 Python
DIY胆机必读:各国电子管评价
2022/04/06 无线电
Pandas 数据编码的十种方法
2022/04/20 Python