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目录操作之python遍历文件夹后将结果存储为xml
Jan 27 Python
python列表去重的二种方法
Feb 14 Python
python 多线程实现检测服务器在线情况
Nov 25 Python
PHP网页抓取之抓取百度贴吧邮箱数据代码分享
Apr 13 Python
python通过opencv实现批量剪切图片
Nov 13 Python
python如何为被装饰的函数保留元数据
Mar 21 Python
python基础教程项目三之万能的XML
Apr 02 Python
解决Django一个表单对应多个按钮的问题
Jul 18 Python
微信公众号token验证失败解决方案
Jul 22 Python
tensorflow模型的save与restore,及checkpoint中读取变量方式
May 26 Python
python中if嵌套命令实例讲解
Feb 25 Python
linux中nohup和后台运行进程查看及终止
Jun 24 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
PHP5.6.8连接SQL Server 2008 R2数据库常用技巧分析总结
2019/05/06 PHP
PHP实现带进度条的Ajax文件上传功能示例
2019/07/02 PHP
PHP 实现 WebSocket 协议原理与应用详解
2020/04/22 PHP
当自定义数据属性为json格式字符串时jQuery的data api问题探讨
2013/02/18 Javascript
js获取指定的cookie的具体实现
2014/02/20 Javascript
使用jquery解析XML的方法
2014/09/05 Javascript
javascript面向对象之对象的深入理解
2015/01/13 Javascript
JQuery显示隐藏DIV的方法及代码实例
2015/04/16 Javascript
javascript实现网页中涉及的简易运动(改变宽高、透明度、位置)
2015/11/29 Javascript
JavaScript判断图片是否已经加载完毕的方法汇总
2016/02/05 Javascript
基于Javascript实现二级联动菜单效果
2016/03/04 Javascript
jQuery实现底部浮动窗口效果
2016/09/07 Javascript
vue.js表格分页示例
2016/10/18 Javascript
JavaScript中${pageContext.request.contextPath}取值问题及解决方案
2016/12/08 Javascript
jQuery+vue.js实现的九宫格拼图游戏完整实例【附源码下载】
2017/09/12 jQuery
React中上传图片到七牛的示例代码
2017/10/10 Javascript
js实现图片区域可点击大小随意改变(适用移动端)代码实例
2019/09/11 Javascript
微信小程序实现时间进度条功能
2020/11/17 Javascript
javascript设计模式 ? 代理模式原理与用法实例分析
2020/04/16 Javascript
Vue2.0 ES6语法降级ES5的操作
2020/10/30 Javascript
[53:38]OG vs LGD 2018国际邀请赛淘汰赛BO3 第三场 8.26
2018/08/30 DOTA
十行代码使用Python写一个USB病毒
2019/06/21 Python
用Python去除图像的黑色或白色背景实例
2019/12/12 Python
解析浏览器的一些“滚动”行为鉴赏
2019/09/16 HTML / CSS
选购世界上最好的美妆品:Cult Beauty
2017/11/03 全球购物
西班牙自行车和跑步商店:Alltricks
2018/07/07 全球购物
英国名牌服装购物网站:OD’s Designer
2019/09/02 全球购物
波兰在线运动商店:YesSport
2020/07/23 全球购物
说一下Linux下有关用户和组管理的命令
2014/08/18 面试题
个人简历自我评价
2014/01/06 职场文书
中专毕业生自我鉴定
2014/02/02 职场文书
《一个中国孩子的呼声》教学反思
2014/02/12 职场文书
乒乓球比赛通知
2015/04/27 职场文书
二十年同学聚会致辞
2015/07/28 职场文书
原生JS中应该禁止出现的写法
2021/05/05 Javascript
用php如何解决大文件分片上传问题
2021/07/07 PHP