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 字典(Dictionary)操作详解
Mar 11 Python
python下调用pytesseract识别某网站验证码的实现方法
Jun 06 Python
Python图算法实例分析
Aug 13 Python
python matplotlib坐标轴设置的方法
Dec 05 Python
利用Python如何实现一个小说网站雏形
Nov 23 Python
Pandas之Fillna填充缺失数据的方法
Jun 25 Python
python读csv文件时指定行为表头或无表头的方法
Jun 26 Python
python文件处理fileinput使用方法详解
Jan 02 Python
Python3 集合set入门基础
Feb 10 Python
pytorch中的inference使用实例
Feb 20 Python
完美解决keras保存好的model不能成功加载问题
Jun 11 Python
python使用pycharm安装pyqt5以及相关配置
Apr 22 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之对抗Web扫描器的脚本技巧
2008/10/01 PHP
DedeCMS 核心类TypeLink.class.php摘要笔记
2010/04/07 PHP
关于shopex同步ucenter的redirect问题,导致script不运行
2013/04/10 PHP
基于preg_match_all采集后数据处理的一点心得笔记(编码转换和正则匹配)
2014/01/31 PHP
9个经典的PHP代码片段分享
2014/12/18 PHP
Laravel 5框架学习之向视图传送数据(进阶篇)
2015/04/08 PHP
Zend Framework教程之模型Model基本规则和使用方法
2016/03/04 PHP
学习PHP session的传递方式
2016/06/15 PHP
php解决和避免form表单重复提交的几种方法
2016/08/31 PHP
ThinkPHP3.1.x修改成功与失败跳转页面的方法
2017/09/29 PHP
JQuery 学习笔记 选择器之六
2009/07/23 Javascript
实用框架(iframe)操作代码
2014/10/23 Javascript
IE中document.createElement的iframe无法设置属性name的解决方法
2015/09/14 Javascript
详解JavaScript实现设计模式中的适配器模式的方法
2016/05/18 Javascript
jquery+Jscex打造游戏力度条
2020/09/12 Javascript
JavaScript判断浏览器对CSS3属性是否支持的多种方法
2016/11/13 Javascript
AngularJS自定义指令实现面包屑功能完整实例
2017/05/17 Javascript
jQuery操作之效果详解
2017/05/19 jQuery
在vue里使用codemirror遇到的问题
2018/11/01 Javascript
Vue动态组件和异步组件原理详解
2019/05/06 Javascript
vue+element项目中过滤输入框特殊字符小结
2019/08/07 Javascript
vue从零实现一个消息通知组件的方法详解
2020/03/16 Javascript
Vue中引入svg图标的两种方式
2021/01/14 Vue.js
Python中itertools模块用法详解
2014/09/25 Python
python实现获取客户机上指定文件并传输到服务器的方法
2015/03/16 Python
python将每个单词按空格分开并保存到文件中
2018/03/19 Python
python实现事件驱动
2018/11/21 Python
使用python serial 获取所有的串口名称的实例
2019/07/02 Python
猎人靴英国官网:Hunter Boots
2017/02/02 全球购物
美国女孩服装购物网站:Justice
2017/03/04 全球购物
医学专业毕业生推荐信
2013/11/14 职场文书
岳父生日宴会答谢词
2014/01/13 职场文书
英语教师求职信
2014/06/16 职场文书
2015年乡镇工作总结范文
2015/04/22 职场文书
「魔法少女伊莉雅」美游粘土人开订
2022/03/21 日漫
vue cli4中mockjs在dev环境和build环境的配置详情
2022/04/06 Vue.js