1、实现多任务最经常使用的两种方法:多线程和多进程服务器
2、要实现多任务,一般咱们会设计 Master-Worker 模式,其中Master 负责分配任务,Worker负责执行任务。所以多任务环境下,一般是一个Master,多个Worker。网络
3、若是用多进程实现 Master-Worker ,主进程就是 Master,其余进程就是 Worker。多线程
若是用多线程实现 Master-Worker ,主线程就是 Master,其余线程就是 Worker。dom
4、多进程优缺点分布式
优势:稳定性高 由于一个子进程奔溃,不会影响主进程和其余子进程;spa
缺点:建立进程的代价大,对硬件的要求较高。线程
5、分布式进程设计
一、在 线程Thread 和 进程Process 中,应当优选Process,由于Process更稳定,并且,Process能够分布到多台机器上,而Thread最多只能分布到同一台机器的多个CPU上。code
二、Python的 multiprocessing
模块不但支持多进程,其中managers
子模块还支持把多进程分布到多台机器上。一个服务进程能够做为调度者,将任务分布到其余多个进程中,依靠网络通讯。因为managers
模块封装很好,没必要了解网络通讯的细节,就能够很容易地编写分布式多进程程序。server
三、例如:若是咱们已经有一个经过Queue
通讯的多进程程序在同一台机器上运行,如今,因为处理任务的进程任务繁重,但愿把发送任务的进程和处理任务的进程分布到两台机器上。怎么用分布式进程实现?
解决:原有的Queue
能够继续使用,可是,经过managers
模块把Queue
经过网络暴露出去,就可让其余机器的进程访问Queue
了。
在服务进程端:服务进程负责启动Queue
,把Queue
注册到网络上,而后往Queue
里面写入任务:
import random import queue import time 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=('192.168.37.128', 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.')
注意:当咱们在一台机器上写多进程时,建立的Queue
能够直接拿来用,可是,在分布式多进程环境下,添加任务到Queue
不能够直接对原始的task_queue
进行操做,那样就绕过了QueueManager
的封装,必须经过manager.get_task_queue()
得到的Queue
接口添加。
在任务进程端:
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') # 从网络链接: 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 * %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.')