如果你打算編寫多進程的服務程序,Unix/Linux無疑是正確的選擇。由于Windows沒有fork調用,難道在Windows上無法用Python編寫多進程的程序?
由于Python是跨平臺的,自然也應該提供一個跨平臺的多進程支持。multiprocessing模塊就是跨平臺版本的多進程模塊。
multiprocessing模塊提供了一個Process類來代表一個進程對象,下面的例子演示了啟動一個子進程并等待其結束:
說明
·創建子進程時,只需要傳入一個執行函數和函數的參數,創建一個Process實例,用start()方法啟動,這樣創建進程比fork()還要簡單。
·join()方法可以等待子進程結束后再繼續往下運行,通常用于進程間的同步。
Process語法結構如下:
Process([group [, target [, name [, args [,kwargs]]]]])
·target:表示這個進程實例所調用對象;
·args:表示調用對象的位置參數元組;
·kwargs:表示調用對象的關鍵字參數字典;
·name:為當前進程實例的別名;
·group:大多數情況下用不到;
Process類常用方法:
·is_alive():判斷進程實例是否還在執行;
·join([timeout]):是否等待進程實例執行結束,或等待多少秒;
·start():啟動進程實例(創建子進程);
·run():如果沒有給定target參數,對這個對象調用start()方法時,就將執行對象中的run()方法;
·terminate():不管任務是否完成,立即終止;
Process類常用屬性:
·name:當前進程實例別名,默認為Process-N,N為從1開始遞增的整數;
·pid:當前進程實例的PID值;
進程的創建-Process子類
創建新的進程還能夠使用類的方式,可以自定義一個類,繼承Process類,每次實例化這個類的時候,就等同于實例化一個進程對象,請看下面的實例:
兩種方式的對比:
1、方法
2、繼承類
繼承類是以面向對象考慮這個事的,所以業務邏輯復雜,建議使用繼承類,更好理解
進程池Pool
當需要創建的子進程數量不多時,可以直接利用multiprocessing中的Process動態成生多個進程,但如果是上百甚至上千個目標,手動的去創建進程的工作量巨大,此時就可以用到multiprocessing模塊提供的Pool方法。
初始化Pool時,可以指定一個最大進程數,當有新的請求提交到Pool中時,如果池還沒有滿,那么就會創建一個新的進程用來執行該請求;但如果池中的進程數已經達到指定的最大值,那么該請求就會等待,直到池中有進程結束,才會創建新的進程來執行,請看下面的實例:
multiprocessing.Pool常用函數解析:
·apply_async(func[, args[, kwds]]):使用非阻塞方式調用func(并行執行,堵塞方式必須等待上一個進程退出才能執行下一個進程),args為傳遞給func的參數列表,kwds為傳遞給func的關鍵字參數列表;
·apply(func[, args[, kwds]]):使用阻塞方式調用func
·close():關閉Pool,使其不再接受新的任務;
·terminate():不管任務是否完成,立即終止;
·join():主進程阻塞,等待子進程的退出,必須在close或terminate之后使用;
apply堵塞式
進程間通信-Queue
Queue的使用
可以使用multiprocessing模塊的Queue實現多進程之間的數據傳遞,Queue本身是一個消息列隊程序,首先用一個小實例來演示一下Queue的工作原理:
說明
初始化Queue()對象時(例如:q=Queue()),若括號中沒有指定最大可接收的消息數量,或數量為負值,那么就代表可接受的消息數量沒有上限(直到內存的盡頭);
·Queue.qsize():返回當前隊列包含的消息數量;
·Queue.empty():如果隊列為空,返回True,反之False;
·Queue.full():如果隊列滿了,返回True,反之False;
·Queue.get([block[, timeout]]):獲取隊列中的一條消息,然后將其從列隊中移除,block默認值為True;
1)如果block使用默認值,且沒有設置timeout(單位秒),消息列隊如果為空,此時程序將被阻塞(停在讀取狀態),直到從消息列隊讀到消息為止,如果設置了timeout,則會等待timeout秒,若還沒讀取到任何消息,則拋出"Queue.Empty"異常;
2)如果block值為False,消息列隊如果為空,則會立刻拋出"Queue.Empty"異常;
·Queue.get_nowait():相當Queue.get(False);
·Queue.put(item,[block[, timeout]]):將item消息寫入隊列,block默認值為True;
1)如果block使用默認值,且沒有設置timeout(單位秒),消息列隊如果已經沒有空間可寫入,此時程序將被阻塞(停在寫入狀態),直到從消息列隊騰出空間為止,如果設置了timeout,則會等待timeout秒,若還沒空間,則拋出"Queue.Full"異常;
2)如果block值為False,消息列隊如果沒有空間可寫入,則會立刻拋出"Queue.Full"異常;
·Queue.put_nowait(item):相當Queue.put(item, False);
進程池中的Queue
如果要使用Pool創建進程,就需要使用multiprocessing.Manager()中的Queue(),而不是multiprocessing.Queue(),否則會得到一條如下的錯誤信息:
RuntimeError: Queue objects should only beshared between processes through inheritance.
下面的實例演示了進程池中的進程如何通信:
?