[英]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(),您就無法知道每個出納員都與人打交道。 您不能在出納員窗口有人的情況下將其送回家。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.