Python多程式程式設計

昀溪發表於2018-08-08

序.multiprocessing

python中的多執行緒其實並不是真正的多執行緒,如果想要充分地使用多核CPU的資源,在python中大部分情況需要使用多程式。Python提供了非常好用的多程式包multiprocessing,只需要定義一個函式,Python會完成其他所有事情。藉助這個包,可以輕鬆完成從單程式到併發執行的轉換。multiprocessing支援子程式、通訊和共享資料、執行不同形式的同步,提供了Process、Queue、Pipe、Lock等元件。

1.Process

建立程式的類:Process([group [, target [, name [, args [, kwargs]]]]]),target表示呼叫物件,args表示呼叫物件的位置引數元組。kwargs表示呼叫物件的字典。name為別名。group實質上不使用。
方法:is_alive()、join([timeout])、run()、start()、terminate()。其中,Process以start()啟動某個程式。

屬性:authkey、daemon(要通過start()設定)、exitcode(程式在執行時為None、如果為–N,表示被訊號N結束)、name、pid。其中daemon是父程式終止後自動終止,且自己不能產生新程式,必須在start()之前設定。

例1.1:建立函式並將其作為單個程式

結果

例1.2:建立函式並將其作為多個程式

結果

例1.3:將程式定義為類

 

:程式p呼叫start()時,自動呼叫run()

結果

例1.4:daemon程式對比結果

#1.4-1 不加daemon屬性

結果

#1.4-2 加上daemon屬性

結果

:因子程式設定了daemon屬性,主程式結束,它們就隨著結束了。

#1.4-3 設定daemon執行完結束的方法

結果

2.Lock

當多個程式需要訪問共享資源的時候,Lock可以用來避免訪問的衝突。

結果(輸出檔案)

3.Semaphore

Semaphore用來控制對共享資源的訪問數量,例如池的最大連線數。

結果

4.Event

Event用來實現程式間同步通訊。

結果

5.Queue

Queue是多程式安全的佇列,可以使用Queue實現多程式之間的資料傳遞。put方法用以插入資料到佇列中,put方法還有兩個可選引數:blocked和timeout。如果blocked為True(預設值),並且timeout為正值,該方法會阻塞timeout指定的時間,直到該佇列有剩餘的空間。如果超時,會丟擲Queue.Full異常。如果blocked為False,但該Queue已滿,會立即丟擲Queue.Full異常。

get方法可以從佇列讀取並且刪除一個元素。同樣,get方法有兩個可選引數:blocked和timeout。如果blocked為True(預設值),並且timeout為正值,那麼在等待時間內沒有取到任何元素,會丟擲Queue.Empty異常。如果blocked為False,有兩種情況存在,如果Queue有一個值可用,則立即返回該值,否則,如果佇列為空,則立即丟擲Queue.Empty異常。Queue的一段示例程式碼: 

結果

 6.Pipe

Pipe方法返回(conn1, conn2)代表一個管道的兩個端。Pipe方法有duplex引數,如果duplex引數為True(預設值),那麼這個管道是全雙工模式,也就是說conn1和conn2均可收發。duplex為False,conn1只負責接受訊息,conn2只負責傳送訊息。

send和recv方法分別是傳送和接受訊息的方法。例如,在全雙工模式下,可以呼叫conn1.send傳送訊息,conn1.recv接收訊息。如果沒有訊息可接收,recv方法會一直阻塞。如果管道已經被關閉,那麼recv方法會丟擲EOFError。 

結果

7.Pool

在利用Python進行系統管理的時候,特別是同時操作多個檔案目錄,或者遠端控制多臺主機,並行操作可以節約大量的時間。當被操作物件數目不大時,可以直接利用multiprocessing中的Process動態成生多個程式,十幾個還好,但如果是上百個,上千個目標,手動的去限制程式數量卻又太過繁瑣,此時可以發揮程式池的功效。
Pool可以提供指定數量的程式,供使用者呼叫,當有新的請求提交到pool中時,如果池還沒有滿,那麼就會建立一個新的程式用來執行該請求;但如果池中的程式數已經達到規定最大值,那麼該請求就會等待,直到池中有程式結束,才會建立新的程式來它。

例7.1:使用程式池

一次執行結果

函式解釋:

  • apply_async(func[, args[, kwds[, callback]]]) 它是非阻塞,apply(func[, args[, kwds]])是阻塞的(理解區別,看例1例2結果區別)
  • close()    關閉pool,使其不在接受新的任務。
  • terminate()    結束工作程式,不在處理未完成的任務。
  • join()    主程式阻塞,等待子程式的退出, join方法要在close或terminate之後使用。

執行說明:建立一個程式池pool,並設定程式的數量為3,xrange(4)會相繼產生四個物件[0, 1, 2, 4],四個物件被提交到pool中,因pool指定程式數為3,所以0、1、2會直接送到程式中執行,當其中一個執行完事後才空出一個程式處理物件3,所以會出現輸出“msg: hello 3”出現在”end”後。因為為非阻塞,主函式會自己執行自個的,不搭理程式的執行,所以執行完for迴圈後直接輸出“mMsg: hark~ Mark~ Mark~~~~~~~~~~~~~~~~~~~~~~”,主程式在pool.join()處等待各個程式的結束。

例7.2:使用程式池(阻塞)

一次執行的結果

例7.3:使用程式池,並關注結果

一次執行結果

例7.4:使用多個程式池

一次執行結果

 

相關文章