簡體   English   中英

Python multiprocessing.Queue 明顯丟失數據

[英]Python multiprocessing.Queue apparently losing data

我正在嘗試利用多處理來加速程序。 為此,我在某些時候需要在盡可能多的進程之間並行化任務,比方說 n。 因為我不想創建超出絕對必要的進程,所以我創建了 n-1 個新進程,啟動它們,然后在當前進程上運行最后的工作,最后將所有內容連接在一起。 所有這些都通過隊列進行通信。 每個進程都通過參數傳遞其“工作份額”,因此每個進程只需要在完成后將結果放入隊列(每個結果的長度約為 6600 個 5 個字母的單詞)。

def play(chosen_word):
    l=[chosen_word, chosen_word]
    return l

def partial_test(id, words, queue):
    print(f'Process {id} started and allocated {len(words)} words.')
    guesses=[]
    for word in words:
        guesses.append(play(word))

    print(f"Process {id} has finished ALL WORDS.") #debugging only
    queue.put((id, guesses))
    print(f'Process {id} added results to queue')
    queue.cancel_join_thread()
    print(f'Process {id} closed the queue and exited. Queue has aproximately {queue.qsize()} elements')


def full_test():
    #do stuff

    #create Queue for results
    queue=Queue()

    #initialize auxiliary processes
    processes=[Process(target=partial_test, args=(x, word_list[x*words_per_process:(x+1)*words_per_process], queue)) for x in range(process_count-1)]

    #start processes
    for process in processes:
        process.start()
    #run last process on the current thread
    partial_test(process_count-1, word_list[(process_count-1)*words_per_process:], queue)

    #join processes
    i=0
    for process in processes:
        process.join()
        print(f'Joined process {i} with main thread.')
        i+=1

    print("All processes finished!")

    #get results (they need to be in order) 
    results=[[] for _ in range(process_count)]
    i=0
    while not queue.empty():
        res=queue.get()
        results[res[0]]=res[1].copy()
        i+=1
    print(f"Got {i} results!")

    #do stuff with results

當我嘗試讀取隊列中的數據時出現問題。 每個進程都報告說它把數據放到了隊列中,所以在最后一個加入之前它有 n 個元素。 但是,當我嘗試獲取它們並將它們放入結果列表時,我只提取了一個元素,其中包含第 n 個進程(我在主線程上運行的進程)記錄的數據。

我最初沒有使用 queue.cancel_join_thread(),但發現為了防止進程加入,即使在完成執行后,它們也會等待緩沖區實際寫入隊列,在大量的情況下數據,在調用 queue.get() 方法之前不會這樣做。 但是因為我只在所有進程完成后才獲取數據,所以永遠不會調用它並且程序會卡住。 我想這可能與此有關(盡管我不明白為什么它不會影響第 n 個進程),但我發現沒有辦法將緩沖區中的數據“強制刷新”到隊列中。

我也確信這部分代碼可能依賴於其他所有 function 返回正確的數據,因為我已經在單進程版本中測試了相同數據的所有內容。

編輯:劇本 function 只是一個替身,但就本文的所有意圖和目的而言,它與原始劇本等同,因為使用它會產生完全相同的問題。 發布原始代碼及其所有依賴項意味着發布我的大部分代碼,這會使我很難集中精力解決問題。

所以,這是你的問題:

我最初沒有使用 queue.cancel_join_thread(),但發現為了防止進程加入,即使在完成執行后,它們也會等待緩沖區實際寫入隊列,在大量的情況下數據,在調用 queue.get() 方法之前不會這樣做。 但是因為我只在所有進程完成后才獲取數據,所以永遠不會調用它並且程序會卡住。 我想這可能與此有關(盡管我不明白為什么它不會影響第 n 個進程),但我發現沒有辦法將緩沖區中的數據“強制刷新”到隊列中。

使用multiprocessing.Queue ,讀者需要在作者寫作的同時閱讀。 隊列是在有界大小的操作系統級管道之上實現的,如果沒有任何內容正在讀取,寫入者將很快填滿管道的緩沖區並變得無法寫入。 你得到的錯誤是由於那個。 您沒有找到“強制刷新”選項,因為沒有地方可以刷新 - pipe 已滿,沒有人正在閱讀以清除它。

cancel_join_thread不能解決問題。 通過調用cancel_join_thread你是在告訴 Python,“不,我真的完全同意你扔掉我的數據” ,所以工作進程愉快地退出而沒有完成對 pipe 的寫入,並扔掉你的數據。 該文檔明確警告說,只有在您不關心丟失的數據時才應使用cancel_join_thread


您可以嘗試使用帶有manager = multiprocessing.Manager()queue = manager.Queue()的托管隊列,因為 IIRC,托管隊列沒有相同的限制,但它們避免此限制的方式涉及創建額外的服務器進程管理隊列,按照您的方式設計程序的全部目的是避免創建額外的進程。 另外,我認為基於管理器的隊列有額外的進程間通信開銷。

我建議只使用multiprocessing.Queue的設計使用方式 - 在寫入的同時讀取它。 不要將主進程用作額外的工作人員,而是讓它在完成啟動工作人員后立即開始讀取數據,並且只有在讀取所有數據后才加入工作人員。

暫無
暫無

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

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