簡體   English   中英

非阻塞 multiprocessing.connection.Listener?

[英]Non-blocking multiprocessing.connection.Listener?

我使用 multiprocessing.connection.Listener 進行進程之間的通信,它對我來說很有魅力。 現在我真的很喜歡我的主循環在來自客戶端的命令之間做其他事情。 不幸的是 listener.accept() 會阻止執行,直到建立來自客戶端進程的連接。

是否有一種簡單的方法來管理 multiprocessing.connection 的非阻塞檢查? 超時? 還是我應該使用專用線程?

    # Simplified code:

    from multiprocessing.connection import Listener

    def mainloop():
        listener = Listener(address=(localhost, 6000), authkey=b'secret')

        while True:
            conn = listener.accept() # <---  This blocks!
            msg = conn.recv() 
            print ('got message: %r' % msg)
            conn.close()

我發現的一種解決方案(盡管它可能不是最“優雅”的解決方案是使用conn.poll 。( 文檔)如果 Listener 有新數據,則 Poll 返回True ,並且(最重要的是)如果沒有參數傳遞給它,則為非阻塞. 我不是 100% 確定這是最好的方法,但我只運行listener.accept()一次就成功了,然后使用以下語法重復獲取輸入(如果有任何可用的)

from multiprocessing.connection import Listener

def mainloop():
    running = True

    listener = Listener(address=(localhost, 6000), authkey=b'secret')
    conn = listener.accept()
    msg = ""

    while running:
        while conn.poll():
            msg = conn.recv() 
            print (f"got message: {msg}")

            if msg == "EXIT":
                running = False

        # Other code can go here
        print(f"I can run too! Last msg received was {msg}")

     conn.close()

如果您只想一次最多獲取一條消息,則條件語句中的“while”可以替換為“if”。 謹慎使用,因為它看起來有點“hacky”,而且我還沒有在其他地方找到將conn.poll用於此目的的參考資料。

我自己沒有使用過 Listener 對象——對於這個任務,我通常使用multiprocessing.Queue doco 在以下鏈接:

https://docs.python.org/2/library/queue.html#Queue.Queue

該對象可用於通過良好的 API 在 Python 進程之間發送和接收任何可腌制的對象; 我想你最感興趣的是:

  • 進程A中
    • .put('some message')
  • 進程B中
    • .get_nowait() # will raise Queue.Empty if nothing is available- handle that to move on with your execution

唯一的限制是您需要在某個時候控制兩個 Process 對象,以便能夠將隊列分配給它們 - 如下所示:

import time
from Queue import Empty
from multiprocessing import Queue, Process


def receiver(q):
    while 1:
        try:
            message = q.get_nowait()
            print 'receiver got', message
        except Empty:
            print 'nothing to receive, sleeping'
            time.sleep(1)


def sender(q):
    while 1:
        message = 'some message'
        q.put('some message')
        print 'sender sent', message
        time.sleep(1)


some_queue = Queue()

process_a = Process(
    target=receiver,
    args=(some_queue,)
)

process_b = Process(
    target=sender,
    args=(some_queue,)
)

process_a.start()
process_b.start()

print 'ctrl + c to exit'
try:
    while 1:
        time.sleep(1)
except KeyboardInterrupt:
    pass

process_a.terminate()
process_b.terminate()

process_a.join()
process_b.join()

隊列很好,因為對於完全相同的 Queue 對象,您實際上可以擁有盡可能多的消費者和生產者(對於分發任務很方便)。

我應該指出,僅在 Process 上調用.terminate()是不好的形式 - 您應該使用閃亮的新消息系統來傳遞關閉消息或類似性質的消息。

多處理模塊帶有一個很好的特性,叫做 Pipe()。 這是在兩個進程之間共享資源的好方法(以前從未嘗試過兩個以上)。 隨着python 3.80的出現,多處理模塊中的共享內存功能出現了,但我還沒有真正測試過,所以我不能保證它你將使用管道功能

from multiprocessing import Pipe

.....

def sending(conn):
    message = 'some message'
    #perform some code
    conn.send(message)
    conn.close()

receiver, sender = Pipe()
p = Process(target=sending, args=(sender,))
p.start()
print receiver.recv()   # prints "some message"
p.join()

有了這個,您應該能夠讓單獨的進程獨立運行,並且當您到達需要來自一個進程的輸入的程度時。 如果由於其他進程的未釋放數據而出現某種錯誤,您可以將其置於某種睡眠或暫停狀態,或使用 while 循環在其他進程完成該任務並將其發送過來時不斷檢查掛起

while not parent_conn.recv():
    time.sleep(5)

這應該將其保持在無限循環中,直到另一個進程完成運行並發送結果。 這也比隊列快 2-3 倍。 盡管隊列也是一個不錯的選擇,但我個人不使用它。

您可以在線程中運行阻塞函數:

conn = await loop.run_in_executor(None, listener.accept)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM