Python基础——进程 vs 线程(0526)

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.')
相关文章
相关标签/搜索