分布式 task_master / task_worker,
17:08:0317:08:04
在Thread(線程)和Process(進程)中,應當優選Process,因為Process更穩定,而且,Process可以分布到多台機器上,而Thread最多隻能分布到同一台機器的多個CPU上。
Python的multiprocessing模組不但支援多進程,其中managers子模組還支援把多進程分布到多台機器上。
一個服務進程可以作為調度者(master),將任務分布到其他多個進程中,依靠網路通訊。由於managers模組封裝很好,不必瞭解網路通訊的細節,就可以很容易地編寫分布式多進程程式。
master/worker 方法已經封裝了socket模組,在其他用途中絕大部分代碼是直接使用的...(Python是思路、方法都高度統一的)
註:win環境下master和worker不能再IDE中直接開啟,只能在DOS中開啟
master主機
#coding=utf-8# tast_master.py'''我們先看服務進程,服務進程負責啟動Queue,把Queue註冊到網路上,然後往Queue裡面寫入任務'''import random, time, queuefrom multiprocessing import freeze_supportfrom multiprocessing.managers import BaseManager# 發送任務的隊列:task_queue = queue.Queue()# 接收結果的隊列:result_queue = queue.Queue()# 從BaseManager繼承的QueueManager:class QueueManager(BaseManager): passdef return_task_queue(): global task_queue return task_queue def return_result_queue(): global result_queue return result_queue# 把兩個Queue都註冊到網路上, callable參數關聯了Queue對象:if __name__=="__main__": #如果你的機器是win32,Run code for process object if this in not the main process freeze_support() ''' 請注意,當我們在一台機器上寫多進程程式時,建立的Queue可以直接拿來用, 但是,在分布式多進程環境下,新增工作到Queue不可以直接對原始的 task_queue進行操作,那樣就繞過了QueueManager的封裝,必須通過 manager.get_task_queue()獲得的Queue介面添加。 ''' QueueManager.register('get_task_queue', callable=return_task_queue) QueueManager.register('get_result_queue', callable=return_result_queue) # 綁定連接埠5000, 設定驗證碼'abc': manager = QueueManager(address=('127.0.0.1', 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=20) print('Result: %s' % r) # 關閉: manager.shutdown() print('master exit.')
worker
#coding=utf-8# tast_worker.pyimport time, sys, queuefrom 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.')