注意细节:关闭防火墙,同一网段
分布式进程
python的 mutiprocessing 模块支持多进程,且其子模块managers 支持分布式,在多台机器上运行。而Thread只能分布在同一台机器的多个CPU上。
发送任务的进程 和处理任务的进程,分布在两台机器上。
注意:同一台机器上写多进程时,Queue队列可以直接使用,但是分布式多进程条件下,添加任务刅Queue不可以直接对原始的task_queue 操作。需要通过封装,继承类BaseManager,获得的新Queue添加。
**
代码
**
task_master.py 和 task_worker.py`
#_*_ conding:utf-8 _*_
#task_master.py
import random,time,queue
from multiprocessing.managers import BaseManager
from multiprocessing import freeze_support
task_queue = queue.Queue() # 发送任务的队列:
result_queue = queue.Queue() # 接收结果的队列:
class QueueManager(BaseManager): # 从BaseManager继承的
pass
# windows下运行
def return_task_queue():
global task_queue
return task_queue # 返回发送任务队列
def return_result_queue ():
global result_queue
return result_queue # 返回接收结果队列
def test():
# 把两个Queue都注册到网络上, callable参数关联了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=('198.8.8.8', 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()
在task_worker.py中:
# task_worker.py
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 = '198.8.8.8'
print('Connect to server %s...' % server_addr)
# 端口和验证码注意保持与task_master.py设置的完全一致:
m = QueueManager(address=(server_addr, 5000), authkey=b'abc')
# 从网络连接:
m.connect()
# 获取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 ' % n)
r = n*n
time.sleep(1)
result.put(r)
except queue.Empty:
print('task queue is empty.')
# 处理结束:
print('worker exit.')
知识补充
QueueManager 实现了Queue的网络访问,但由于QueueManager管理的不止一个Queue,所以需要给每个Queue的网络调用接口取名字,比如此处的get_task_queue。 task_worker.py中注册的名字必须和task_manager中注册的一致authkey也需一致。