Python的multiprocessing模块不但支持多进程,其中managers子模块还支持把多进程分布到多台机器上.一个服务进程可以作为调度者,将任务分布到其他多个进程中,依靠网络通信.由于managers模块封装把网络通信的都给封装好了,所以即使我们不了解网络通信,也能写出分布式多进程程序.
为什么使用分布式进程
如果我们的一个通过Queue通信的多进程程序在一台机器上运行.随着要处理的任务越来越繁重,甚至一台机器根本都没法完成了.我们能想到什么?肯定是想到把这些任务分发到多台机器上来做了,这样的话,就需要使用分布式进程了.
如何实现
实现其实不难.原有的Queue继续使用,然后通过managers模块, 在master节点把Queue注册到网络中,worker节点就可以访问到注册在网络中的Queue了。
看下面的案例:
master节点代码
# task.py
from multiprocessing.managers import BaseManager
from multiprocessing import Process, Queue
import time
class Master(object):
# 创建一个分布式管理器
def start_Manager(self,member_q,result_q):
# 把创建的两个队列注册在网络上,利用register方法,callable参数关联了Queue对象,
# 将Queue对象在网络中暴露
BaseManager.register('get_task_queue',callable=lambda:member_q)
BaseManager.register('get_result_queue',callable=lambda:result_q)
// 地址使用master端的地址
manager = BaseManager(address=('', 5000), authkey='abc'.encode('utf-8'))
return manager
def put(self, member_q, result_q):
i = 0
while True:
string = "写入数据_%s" % i
print string
member_q.put(string)
i += 1
time.sleep(1)
def get(self, member_q, result_q):
while True:
if not result_q.empty():
result = result_q.get()
print "result队列读出结果:%s" %result
time.sleep(1)
else:
time.sleep(1)
if __name__ == "__main__":
member_q = Queue()
result_q = Queue()
#创建分布式管理器
node = Master()
manager = node.start_Manager(member_q,result_q)
# manager.start()
// 创建两个进程多和写queue队列的数据
p_put = Process(target=node.put, args=(member_q, result_q,))
p_get = Process(target=node.get, args=(member_q, result_q,))
p_get.start()
p_put.start()
# p_put.join()
# p_get.join()
// 开启服务
manager.get_server().serve_forever()
# manager.shutdown()
worker节点
# coding:utf-8
import time
from multiprocessing.managers import BaseManager
class Node(object):
# 初始化分布式进程中的工作节点的连接工作
def __init__(self):
BaseManager.register('get_task_queue')
BaseManager.register('get_result_queue')
// 地址使用master端的地址
server_addr = '127.0.0.1'
print(('Connect to server %s...' % server_addr))
self.m = BaseManager(address=(server_addr, 5000), authkey='abc'.encode('utf-8'))
self.m.connect()
# 获取在网络中注册的Queue的对象:
self.task = self.m.get_task_queue()
self.result = self.m.get_result_queue()
def work(self):
while True:
try:
if not self.task.empty():
t = self.task.get()
print "队列中取出数据:",t
time.sleep(0.5)
else:
print "task队列为空"
time.sleep(1)
s = "返回结果"
self.result.put(s)
except EOFError as e:
print("连接工作节点失败")
return
except Exception as e:
print(e)
print('Crawl fail ')
if __name__ == "__main__":
n = Node()
n.work()
这样的话,在master节点写进Queue队列中的数据,在worker节点可以读取到,同时,worker节点也可以向Queue队列写数据,同样,在master端也可以读到worker节点写的数据.
实际上,我们的爬虫就可以我们可以利用以上通信方式,开发出分布式爬虫.后续会把利用此开发的分布式爬虫共享一下.