分布式进程:
在Thread和Process中,应当优选Process,因为Process更稳定,而且,Process可以分布到多台机器上,而Thread最多只能分布到同一台机器的多个CPU上。

Python的multiprocessing模块不但支持多进程,其中managers子模块还支持把多进程分布到多台机器上。一个服务进程可以作为调度者,将任务分布到其他多个进程中,依靠网络通信。由于managers模块封装很好,不必了解网络通信的细节,就可以很容易地编写分布式多进程程序。

举个例子:如果我们已经有一个通过Queue通信的多进程程序在同一台机器上运行,现在,由于处理任务的进程任务繁重,希望把发送任务的进程和处理任务的进程分布到两台机器上。怎么用分布式进程实现?

原有的Queue可以继续使用,但是,通过managers模块把Queue通过网络暴露出去,就可以让其他机器的进程访问Queue了。

我们先看服务进程,服务进程负责启动Queue,把Queue注册到网络上,然后往Queue里面写入任务:

下面的代码是在windows下运行的,所以出现了各种问题:

# coding=utf-8
import random, time, Queue
from multiprocessing.managers import BaseManager# 发送任务的队列:
task_queue =Queue.Queue()
# 接收结果的队列:
result_queue = Queue.Queue()# 从BaseManager继承的QueueManager:
class QueueManager(BaseManager):pass# 把两个Queue都注册到网络上, callable参数关联了Queue对象:
QueueManager.register('get_task_queue', callable=lambda: task_queue)
QueueManager.register('get_result_queue', callable=lambda: result_queue)
# 绑定端口5000, 设置验证码'abc':
manager = QueueManager(address=('', 5000), authkey=b'abc')
# 启动Queue:
manager.start()
# 获得通过网络访问的Queue对象:
task = manager.get_task_queue()
result = manager.get_result_queue()
# 放几个任务进去:
for i in range(10):n = random.randint(0, 10000)print('Put task %d...' % n)task.put(n)
# 从result队列读取结果:
print('Try get results...')
for i in range(10):r = result.get(timeout=10)print('Result: %s' % r)
# 关闭:
manager.shutdown()
print('master exit.')

在windows命令行终端的运行结果:

由错误信息改代码:

# coding=utf-8import random,time,  Queue
from multiprocessing.managers import BaseManager
from multiprocessing import freeze_supporttask_queue =  Queue.Queue()  # 发送任务的队列:
result_queue = Queue.Queue() # 接收结果的队列:
class QueueManager(BaseManager):  # 从BaseManager继承的QueueManager:pass
# windows下运行
def return_task_queue():global task_queuereturn task_queue  # 返回发送任务队列
def return_result_queue ():global result_queuereturn result_queue # 返回接收结果队列def test():# 把两个Queue都注册到网络上, callable参数关联了Queue对象,它们用来进行进程间通信,交换对象#QueueManager.register('get_task_queue', callable=lambda: task_queue)#QueueManager.register('get_result_queue', callable=lambda: result_queue)QueueManager.register('get_task_queue', callable=return_task_queue)   QueueManager.register('get_result_queue', callable=return_result_queue)# 绑定端口5000, 设置验证码'abc':#manager = QueueManager(address=('', 5000), authkey=b'abc')# windows需要写ip地址manager = QueueManager(address=('127.0.0.1', 5000), authkey=b'abc')manager.start()  # 启动Queue: # 获得通过网络访问的Queue对象:task = manager.get_task_queue()  result = manager.get_result_queue()for i in range(10):   # 放几个任务进去:n = random.randint(0, 10000)print('Put task %d...' % n)task.put(n)# 从result队列读取结果:print('Try get results...')  for i in range(10):# 这里加了异常捕获try:r = result.get(timeout=5)print('Result: %s' % r)except Queue.Empty:print('result queue is empty.')# 关闭:         manager.shutdown()  print('master exit.')
if __name__=='__main__':freeze_support()print('start!')test()

运行结果:

对比上段代码改变的地方有:

# 把两个Queue都注册到网络上, callable参数关联了Queue对象
QueueManager.register('get_task_queue',callable=return_task_queue)
QueueManager.register('get_result_queue',callable=return_result_queue)

其中task_queue和result_queue是两个队列,分别存放任务和结果。它们用来进行进程间通信,交换对象。

官网上有如下例子。

# coding=utf-8
from multiprocessing import Process, Queue
def f(queue):queue.put([42, None, 'hello'])if __name__ == '__main__': q = Queue() # 创建队列qp = Process(target=f, args=(q,)) # 创建一个进程p.start()print(q.get()) # 打印列表[42, None, 'hello']p.join()

其中列表[42, None, ‘hello’]从新建p进程传到了主进程中。

因为是分布式的环境,放入queue中的数据需要等待Workers机器运算处理后再进行读取,这样就需要对queue用QueueManager进行封装放到网络中。这是通过下面这句

QueueManager.register('get_task_queue',callable=return_task_queue)

实现的,我们给return_task_queue的网络调用接口取了一个名get_task_queue,而return_result_queue的名字是get_result_queue,方便区分对哪个queue进行操作。

task.put(n)即是对task_queue进行写入数据,相当于分配任务。而result.get()即是等待workers处理后返回的结果

 # windows需要写ip地址manager = QueueManager(address=('127.0.0.1', 5000), authkey=b'abc')

这点不同于linux操作系统,必须写ip地址

if __name__=='__main__':freeze_support()print('start!')test()

windows必须有 if name==’main‘: 这点从报错的信息可以看出

中间加入了捕获异常,使代码运行完整,运行结果更容易看懂,在运行的时候最好用cmd终端。

下面是Worker的代码:

# coding=utf-8
import time, sys,Queue
from multiprocessing.managers import BaseManager# 创建类似的QueueManager:
class QueueManager(BaseManager):pass# 由于这个QueueManager只从网络上获取Queue,所以注册时只提供名字:
QueueManager.register('get_task_queue')
QueueManager.register('get_result_queue')# 连接到服务器,也就是运行task_master.py的机器:
server_addr = '127.0.0.1'
print('Connect to server %s...' % server_addr)
# 端口和验证码注意保持与task_master.py设置的完全一致:
m = QueueManager(address=(server_addr, 5000), authkey=b'abc')
# 从网络连接:
try:m.connect()
except:print('请先启动task_master.py!')#sys.exit("sorry, goodbye!");
# 获取Queue的对象:
task = m.get_task_queue()
result = m.get_result_queue()
# 从task队列取任务,并把结果写入result队列:
for i in range(10):try:n = task.get(timeout=1)print('run task %d * %d...' % (n, n))r = '%d * %d = %d' % (n, n, n*n)time.sleep(1)result.put(r)except Queue.Empty:print('task queue is empty.')
# 处理结束:
print('worker exit.')

这个简单的Master/Worker模型有什么用?其实这就是一个简单但真正的分布式计算,把代码稍加改造,启动多个worker,就可以把任务分布到几台甚至几十台机器上,比如把计算n*n的代码换成发送邮件,就实现了邮件队列的异步发送。
Queue对象存储在哪?注意到task_worker.py中根本没有创建Queue的代码,所以,Queue对象存储在task_master.py进程中:

task_worker这里的QueueManager注册的名字必须和task_manager中的一样。对比上面的例子,可以看出Queue对象从另一个进程通过网络传递了过来。只不过这里的传递和网络通信由QueueManager完成。

运行结果:

运行task_master.py

运行task_worker.py

此运行是在同一台电脑上

参考:

https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001431929340191970154d52b9d484b88a7b343708fcc60000

python分布式进程(windows下)相关推荐

  1. 使用Python批量删除windows下特定目录的N天前的旧文件实战:Windows下批量删除旧文件、清除缓存文件、解救C盘、拒绝C盘爆炸

    使用Python批量删除windows下特定目录的N天前的旧文件实战:Windows下批量删除旧文件.清除缓存文件.解救C盘.拒绝C盘爆炸 目录

  2. python定时开关机的代码_用python写一个windows下的定时关机脚本(推荐)

    由于本人经常使用笔记本共享WiFi,但是又不想笔记本开机一夜(为了低碳环保嘛 ~_~!),所以每次都要用使用DOS命令关机,感觉好麻烦.正好最近在学习Python,于是决定用python写一个定时关机 ...

  3. Python(pycharm)在windows下路径 ( ' / ' 与' \ ' )的问题

    1.0 首先了解Python中与pycharm,windows交互的模块(这二个模块可以避免出现路径错误的问题) sys模块 (侧重Python与pycharm交互) 提供的与路径相关的方法有: __ ...

  4. 用python写一个windows下的定时关机脚本

    由于本人经常使用笔记本共享WiFi,但是又不想笔记本开机一夜(为了低碳环保嘛 ~_~!),所以每次都要用使用DOS命令关机,感觉好麻烦.正好最近在学习python,于是决定用python写一个定时关机 ...

  5. python笔记:Windows下的 python-ldap 安装

    Windows下的 python-ldap 安装 https://www.lfd.uci.edu/~gohlke/pythonlibs/#python-ldap 下载: python_ldap-3.3 ...

  6. python 学习之Windows 下的编码处理!

    问题1: 1 Non-ASCII character '\xe9' in file 问题原因:程序编码上出现问题 解决方法:在程序头部加上代码 #-*- coding: UTF-8 -*- 设置代码编 ...

  7. [Python爬虫] 在Windows下安装PIP+Phantomjs+Selenium

    最近准备深入学习Python相关的爬虫知识了,如果说在使用Python爬取相对正规的网页使用"urllib2 + BeautifulSoup + 正则表达式"就能搞定的话:那么动态 ...

  8. [Python爬虫] 在Windows下安装PhantomJS和CasperJS及入门介绍(上)

    最近在使用Python爬取网页内容时,总是遇到JS临时加载.动态获取网页信息的困难.例如爬取CSDN下载资源评论.搜狐图片中的"原图"等,此时尝试学习Phantomjs和Caspe ...

  9. python进阶(四) windows下虚拟环境使用

    虚拟环境作用: 1. 通常开发一个项目,会安装很多的第三方包,这时第三方包我们是安装在本机环境的.那么如果项目进行部署或移植的时候是不是要重新安装这些包???? 2.开发环境,同时在做两相项目,同时要 ...

最新文章

  1. ansys选择一个面上所有节点_如何使用ANSYS经典界面的选择工具
  2. activemq无账户密码登录配置修改
  3. DL之GCN:GCN算法的简介(论文介绍)、架构详解、案例应用等配图集合之详细攻略
  4. JUC系列(十一) | Java 8 CompletableFuture 异步编程
  5. webpack 教程 那些事儿05-多页应用
  6. 泰山行宫碧霞元君祠_临清市泰山行宫碧霞元君祠5月4号(农历三月三十日)举行大型泰山奶奶接驾法会...
  7. Uvaoj10054 - The Necklace
  8. java 反射 方法 修饰符_超类中使用默认修饰符的Java反射访问方法
  9. [直观学习排序算法] 视觉直观感受若干常用排序算法
  10. Locust接口压力测试
  11. 如何用小米玩华为游戏华为账号
  12. cmd的常用命令分类详解
  13. jupyter代码字体大小_Jupyter Notebook 更改字体、字体大小、行高
  14. php 模拟登陆微信,PHP微信模拟登陆并给用户发送消息的方法
  15. 客服坐席聊天页面html,WebSocket实现简单客服聊天系统
  16. 计算机仿真和vr的区别,你真的知道AR与VR的区别吗?
  17. mysql order by file_深聊MySQL,从入门到入坟之:如何让order by、group by查询速度飞起来...
  18. Serval and Rooted Tree(CF1153D)-DP
  19. 牛客网暑期ACM多校训练营(第六场) C.Generation I (思维+逆元+组合数学)
  20. C++保存与读取matlab的mat文件

热门文章

  1. VTK:几何对象之Cube
  2. OpenCV绘图和文本输出功能的实例(附完整代码)
  3. C语言指针与强制类型转换
  4. QT的QHistoryState类的使用
  5. QT的QCache类的使用
  6. json转java对象_json转java对象
  7. sessionFactory.getCurrent()和sessionFactory.openSession()的区别
  8. Mysql迁移到Oracle方法
  9. java socket通信demo_Java Socket通信示例
  10. 中如何使用echart_jQueryEasyUI中的拖拽事件如何使用