簡體   English   中英

"盡管隊列已滿,但 Python 多處理隊列 get() 超時"

[英]Python multiprocessing queue get() timeout despite full queue

我正在使用 Python 的多處理模塊來進行科學的並行處理。 在我的代碼中,我使用了幾個執行繁重工作的工作進程和一個將結果保存到磁盤的寫入器進程。 要寫入的數據通過隊列從工作進程發送到寫入進程。 數據本身相當簡單,僅由一個包含文件名的元組和一個帶有兩個浮點數的列表組成。 經過幾個小時的處理后,編寫器進程通常會卡住。 更准確地說,下面的代碼塊

while (True):
    try:
        item = queue.get(timeout=60)
        break
    except Exception as error:
        logging.info("Writer: Timeout occurred {}".format(str(error)))

永遠不會退出循環,我會收到連續的“超時”消息。

我還實現了一個日志記錄過程,它輸出隊列的狀態等,即使我收到上面的超時錯誤消息,對 qsize() 的調用也會不斷返回一個完整的隊列(在我的例子中是 size=48)。

我已經徹底檢查了有關隊列對象的文檔,但找不到可能的解釋為什么 get() 在隊列滿時返回超時。

有任何想法嗎?

編輯:

我修改了代碼以確保捕獲空隊列異常:

while (True):
    try:
        item = queue.get(timeout=60)
        break
    except Empty as error:
        logging.info("Writer: Timeout occurred {}".format(str(error)))

在多處理隊列中用作同步消息隊列。 在您的問題中似乎也是這種情況。 然而,這需要的不僅僅是調用get()方法。 處理task_done()每個任務后,您需要調用task_done()以便從隊列中刪除該元素。

來自文檔:

Queue.task_done()

表示以前排隊的任務已完成。 由隊列使用者線程使用。 對於用於獲取任務的每個get(),對task_done()的后續調用會告知隊列該任務的處理已完成。

如果join()當前正在阻塞,則它將在所有項目都已處理后恢復(這意味着已為每個已放入隊列的項目收到task_done()調用)。

在文檔中,您還可以找到正確的線程隊列使用的代碼示例。

如果您的代碼應該是這樣的

while (True):
    try:
        item = queue.get(timeout=60)
        if item is None:
            break
        # call working fuction here
        queue.task_done()
    except Exception as error:
        logging.info("Writer: Timeout occurred {}".format(str(error)))

您正在捕獲一個過於通用的Exception並假設它是一個超時錯誤。

嘗試修改邏輯如下:

from Queue import Empty

while (True):
    try:
        item = queue.get(timeout=60)
        break
    except Empty as error:
        logging.info("Writer: Timeout occurred {}".format(str(error)))
        print(queue.qsize())

並查看是否仍然打印了日志。

切換到基於管理器的隊列應該有助於解決此問題。

manager = Manager()
queue   = manager.Queue()

有關更多詳細信息,請在此處查看多處理文檔: https//docs.python.org/2/library/multiprocessing.html

我修改了代碼以確保我捕獲了一個空隊列異常

問題不在於異常處理。 還有一個問題。

Process不會在其他人之間共享內存,而Thread不會發生相同的問題,因為它們共享內存。

讓我們觀察一下使用ProcessThread的代碼是如何工作的。

隊列更改僅對更改它的進程可見

from queue import Queue
from multiprocessing import Process

q = Queue()

def set_data(q):
    q.put("hello")

def get_data(q):
    print(q.get())

p1 = Process(target=get_data, args=(q,))
p2 = Process(target=set_data, args=(q,))

# Wait for queue
p1.start()

# Put data in queue
p2.start()

輸出:什么都沒有發生

線程外部可見的隊列更改

from queue import Queue
from threading import Thread

q = Queue()

def set_data(q):
    q.put("hello")

def get_data(q):
    print(q.get())

t1 = Thread(target=get_data, args=(q,))
t2 = Thread(target=set_data, args=(q,))

# Wait for queue
t1.start()

# Put data in queue
t2.start()

輸出:你好

因此,如果必須使用multiprocessing.Manager ,則必須使用multiprocessing.Process

暫無
暫無

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

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