![](/img/trans.png)
[英]with concurrent.futures.ThreadPoolExecutor() as executor: … does not wait
[英]ThreadPoolExecutor and as_completed: does it wait for all futures to complete?
我有一個用例,我需要處理幾個“任務”對象。 這些Tasks對象基本上都是web爬蟲。 每當任務完成時,我想盡快重新啟動它,使用相同的參數。
這就是我現在所擁有的:
tasks = create_collection_tasks()
with concurrent.futures.ThreadPoolExecutor(max_workers=len(tasks)) as executor:
# Maps the future to a collection task. The mapping is in this direction bc
# later on we can only iterate over the completed futures.
futures_to_tasks = {
executor.submit(task.callback, task.data): task for task in tasks
}
while futures_to_tasks:
for future in concurrent.futures.as_completed(futures_to_tasks):
# If the future raised an exception, calling result() will re-raise
try:
future.result()
except Exception:
logger.exception("Collection task failed")
# When the future is done (completed or crashed/cancelled), put it back
# in the 'queue' to re-run it
task = futures_to_tasks.pop(future)
futures_to_tasks[executor.submit(task.callback, task.data)] = task
我已經閱讀了as_completed
的文檔: https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.as_completed ,但是我仍然不清楚它的行為。 現在,我不知道as_completed
是否在調用它時對futures_to_tasks
中的期貨進行“快照”,並在完成循環之前等待所有這些期貨完成,或者它是否只是通過期貨並產生那些已經完成的,無需等待其他的。 我寧願有以后的行為。
你能幫我一把嗎?
讓我們假設您希望無限期地運行(這似乎暗示在您的問題中)。 您可以考慮這種模式(解釋遵循代碼):
from concurrent.futures import ThreadPoolExecutor
from time import sleep
def trun(v):
print(v)
sleep(0.5)
with ThreadPoolExecutor() as executor:
tasks = ['a', 'b', 'c', 'd', 'e']
futures = dict()
while True:
sleep(0.5)
for i, t in enumerate(tasks):
if (f := futures.get(i, None)) is not None:
if not f.running():
print(f'Thread {i} has finished. Awaiting result')
f.result()
print(f'Restarting thread {i}')
else:
print(f'Thread {i} still running')
continue
else:
print(f'Starting new thread {i}')
futures[i] = executor.submit(trun, t)
我們有許多由任務列表中的字符串表示的任務。
我們構建了一個字典,其鍵將是任務的索引,關聯的值將是 Future object。 在這種特殊情況下,我們可以使用列表中的值作為鍵,但這在現實世界中可能不合適。
有硬編碼的延遲只是為了模擬真實的工作。 您需要考慮一個線程實際上會運行多長時間,以確定您是否需要延遲生產(以避免在while循環中顛簸)。
枚舉任務並檢查我們的字典中是否有對任務 ID(列表索引)的引用。 如果有,請檢查它是否仍在運行。 如果有,獲取結果。
其他一切都應該是不言自明的。
此代碼是可運行的,但您需要手動停止它(Ctrl-C 是理想的)
您可以考慮使用某種形式的哨兵,該哨兵將在線程中設置以指示完成,並且可以在主循環中進行檢查。 但是,如果處理得天真,則存在潛在的競爭條件
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.