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.')