簡體   English   中英

Python - queue.task_done() 用於什么?

[英]Python - What is queue.task_done() used for?

我編寫了一個腳本,該腳本具有多個線程(使用threading.Thread創建queue.get_nowait() ,使用queue.get_nowait()Queue獲取 URL,然后處理 HTML。 我是多線程編程的queue.task_done() ,無法理解queue.task_done()函數的用途。

Queue為空時,它會自動返回queue.Empty異常。 所以我不明白每個線程都需要調用task_done()函數。 我們知道當隊列為空時我們已經完成了隊列,那么為什么我們需要通知它工作線程已經完成了他們的工作(這與隊列無關,在他們從中獲取了 URL 之后) ?

有人可以給我提供一個代碼示例(最好使用urllib 、文件 I/O 或斐波那契數字以外的其他東西並打印“Hello”),向我展示如何在實際應用程序中使用此函數?

Queue.task_done不是為了工人的利益。 它在那里支持Queue.join


如果我給你一盒工作任務,我會在乎你什么時候把所有東西都拿出來了嗎?

不。我關心工作什么時候完成 看着一個空盒子並不能告訴我這一點。 你和其他 5 個人可能仍在研究你開箱即用的東西。

Queue.task_done讓工作人員在任務完成時說。 等待使用Queue.join完成所有工作的Queue.join將等到完成足夠多的task_done調用,而不是在隊列為空時。

.task_done()用於標記.join()處理完成。

💡 如果您使用.join()並且不為每個處理的項目調用.task_done() ,您的腳本將永遠掛起。


就像一個簡短的例子一樣;

import logging
import queue
import threading
import time

items_queue = queue.Queue()
running = False


def items_queue_worker():
    while running:
        try:
            item = items_queue.get(timeout=0.01)
            if item is None:
                continue

            try:
                process_item(item)
            finally:
                items_queue.task_done()

        except queue.Empty:
            pass
        except:
            logging.exception('error while processing item')


def process_item(item):
    print('processing {} started...'.format(item))
    time.sleep(0.5)
    print('processing {} done'.format(item))


if __name__ == '__main__':
    running = True

    # Create 10 items_queue_worker threads
    worker_threads = 10
    for _ in range(worker_threads):
        threading.Thread(target=items_queue_worker).start()

    # Populate your queue with data
    for i in range(100):
        items_queue.put(i)

    # Wait for all items to finish processing
    items_queue.join()

    running = False

有人可以給我提供一個代碼示例(最好使用 urllib、文件 I/O 或斐波那契數字以外的其他東西並打印“Hello”),向我展示如何在實際應用程序中使用此函數?

@ user2357112 的回答很好地解釋了task_done的目的,但缺少請求的示例。 這是一個計算任意數量文件的校驗和並返回一個將每個文件名映射到相應校驗和的字典的函數。 在函數內部,工作被分成幾個線程。

該函數使用Queue.join等待工作人員完成分配的任務,因此將字典返回給調用者是安全的。 這是一種等待所有文件被處理的便捷方式,而不是僅僅將它們出列。

import threading, queue, hashlib

def _work(q, checksums):
    while True:
        filename = q.get()
        if filename is None:
            q.put(None)
            break
        try:
            sha = hashlib.sha256()
            with open(filename, 'rb') as f:
                for chunk in iter(lambda: f.read(65536), b''):
                    sha.update(chunk)
            checksums[filename] = sha.digest()
        finally:
            q.task_done()

def calc_checksums(files):
    q = queue.Queue()
    checksums = {}
    for i in range(1):
        threading.Thread(target=_work, args=(q, checksums)).start()
    for f in files:
        q.put(f)
    q.join()
    q.put(None)  # tell workers to exit
    return checksums

關於 GIL 的說明:由於hashlib的代碼在計算校驗和時在內部釋放 GIL,因此與單線程變體相比,使用多線程會產生可測量的(1.75x-2x,取決於 Python 版本)加速。

“閱讀消息來源,盧克!” ——歐比一科多比

ayncio.queue的源代碼很短。

  • 當您放入隊列時,未完成的任務數增加一。
  • 當你調用 task_done 時它​​會下降一個
  • join() 等待沒有未完成的任務。

當且僅當您調用 task_done() 時,這使得 join 有用。 使用經典的銀行類比:

  • 人們進門排隊; 門是一個生產者做 q.put()
  • 當櫃員空閑而有人在排隊時,他們會去櫃員窗口。 出納員做了一個 q.get()
  • 當出納員完成幫助這個人時,他們就准備好迎接下一個。 出納員做了一個 q.task_done()
  • 下午5點,門鎖門任務完成
  • 你等到兩條線都空了每個出納員都完成了幫助他們面前的人。 等待 q.join(櫃員)
  • 然后你把出納員送回家,他們現在都空着隊列閑着。 對於出納員中的出納員:teller.cancel()

如果沒有 task_done(),您就無法知道每個出納員都與人打交道。 您不能在出納員窗口有人的情況下將其送回家。

暫無
暫無

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

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