【python】詳解multiprocessing多進程-Queue、Pipe進程間通信(三)

       之前專門寫過queue這個庫的使用,詳見文章:詳解queue隊列(一),此處的隊列與原文基本上相近。當使用多個進程時,通常使用消息傳遞來進行進程之間的通信,並避免必須使用任何同步原語(如鎖)。對於傳遞消息,可以使用Pipe()(用於兩個進程之間的連接)或隊列Queue(允許多個生產者和消費者)
       multiprocessing使用通常queue.Empty和 queue.Full異常來發出超時信號。它們在multiprocessing命名空間中不可用,因此需要從中導入它們 queue。

       Queue 用來在多個進程間通信。Queue 有兩個方法,get 和 put:

class multiprocessing.Queue([ maxsize ] )
  • put:放數據,Queue.put( )默認有block=True和timeout兩個參數。當block=True時,寫入是阻塞式的,阻塞時間由timeout確定。當隊列q被(其他線程)寫滿後,這段代碼就會阻塞,直至其他線程取走數據。Queue.put()方法加上 block=False 的參數,即可解決這個隱蔽的問題。但要注意,非阻塞方式寫隊列,當隊列滿時會拋出 exception Queue.Full 的異常

  • get:取數據(默認阻塞),Queue.get([block[, timeout]])獲取隊列,timeout等待時間

from multiprocessing import Process, Queue
import os, time, random
# 寫數據進程執行的代碼:
def _write(q,urls):
    print('Process(%s) is writing...' % os.getpid())
    for url in urls:
        q.put(url)
        print('Put %s to queue...' % url)
        time.sleep(random.random())
# 讀數據進程執行的代碼:
def _read(q):
    print('Process(%s) is reading...' % os.getpid())
    while True:
        url = q.get(True)
        print('Get %s from queue.' % url)
if __name__=='__main__':
    # 父進程創建Queue,並傳給各個子進程:
    q = Queue()
    _writer1 = Process(target=_write, args=(q,['url_1', 'url_2', 'url_3']))
    _writer2 = Process(target=_write, args=(q,['url_4','url_5','url_6']))
    _reader = Process(target=_read, args=(q,))
    # 啓動子進程_writer,寫入:
    _writer1.start()
    _writer2.start()
    # 啓動子進程_reader,讀取:
    _reader.start()
    # 等待_writer結束:
    _writer1.join()
    _writer2.join()
    # _reader進程裏是死循環,無法等待其結束,只能強行終止:
    _reader.terminate()
'''
Process(7460) is writing...
Put url_1 to queue...
Process(13764) is writing...
Put url_4 to queue...
Process(13236) is reading...
Get url_1 from queue.
Get url_4 from queue.
Put url_2 to queue...
Get url_2 from queue.
Put url_5 to queue...
Get url_5 from queue.
Put url_6 to queue...
Get url_6 from queue.
Put url_3 to queue...
Get url_3 from queue.

'''

       Pipe常用來在兩個進程間通信,兩個進程分別位於管道的兩端。

multiprocessing.Pipe([duplex])
(con1, con2) = Pipe()  
  • con1管道的一端,負責存儲,也可以理解爲發送信息
  • con2管道的另一端,負責讀取,也可以理解爲接受信息
from multiprocessing import Process, Pipe

def send(pipe):
    pipe.send(['spam'] + [42, 'egg'])   # send 傳輸一個列表
    pipe.close()

if __name__ == '__main__':
    (con1, con2) = Pipe()                            # 創建兩個 Pipe 實例
    sender = Process(target=send, args=(con1, ))     # 函數的參數,args 一定是實例化之後的 Pipe 變量,不能直接寫 args=(Pip(),)
    sender.start()                                   # Process 類啓動進程
    print("con2 got: %s" % con2.recv())              # 管道的另一端 con2 從send收到消息
    con2.close()                                     # 關閉管道

管道是可以同時發送和接受消息的:

from multiprocessing import Process, Pipe

def talk(pipe):
    pipe.send(dict(name='Bob', spam=42))            # 傳輸一個字典
    reply = pipe.recv()                             # 接收傳輸的數據
    print('talker got:', reply)

if __name__ == '__main__':
    (parentEnd, childEnd) = Pipe()                  # 創建兩個 Pipe() 實例,也可以改成 conf1, conf2
    child = Process(target=talk, args=(childEnd,))  # 創建一個 Process 進程,名稱爲 child
    child.start()                                   # 啓動進程
    print('parent got:', parentEnd.recv())          # parentEnd 是一個 Pip() 管道,可以接收 child Process 進程傳輸的數據
    parentEnd.send({x * 2 for x in 'spam'})         # parentEnd 是一個 Pip() 管道,可以使用 send 方法來傳輸數據
    child.join()                                    # 傳輸的數據被 talk 函數內的 pip 管道接收,並賦值給 reply
    print('parent exit')

'''
parent got: {'name': 'Bob', 'spam': 42}
talker got: {'ss', 'mm', 'pp', 'aa'}
parent exit
'''
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章