[英]Producer-consumer with one producer and several consumers
我正在嘗試通過使用 asyncio 來實現 Producer-Consumer model,它允許生產者將n
項目放入隊列中,然后創建n
消費者以並發方式處理n
項目。
這是我迄今為止的嘗試:
import asyncio
import uuid
import time
import random
async def produce(q, interval=1):
while True:
n = random.randint(0, 20)
for _ in range(n):
await q.put((uuid.uuid4().hex, time.perf_counter()))
await asyncio.sleep(interval)
async def consume(item, t):
print(f"Managing {item}...")
await asyncio.sleep(1)
print(f"Item managed after {time.time() - t:.2f} s")
async def manage_events(q):
while True:
item, t = await q.get()
print(f"Consuming {item}. In queue: {time.perf_counter() - t}")
task = asyncio.create_task(consume(item, time.time()), name=str(item))
print("After manage_item")
async def main():
q = asyncio.Queue()
await asyncio.gather(produce(q, 2), manage_events(q))
if __name__ == "__main__":
s = time.perf_counter()
asyncio.run(main())
elapsed = time.perf_counter() - s
print(f"{__file__} executed in {elapsed:0.2f} seconds")
每個interval
秒,都會創建 0 到 20 個項目並將其放入隊列q
中。 在 function manage_events
中,每次從隊列中提取項目時,都會創建一個異步任務以使用該項目。
這工作得很好,但我的問題是,當看到並發圖時,消費第一個項目的任務在消費完成后並沒有消亡,所以這些任務在僵屍 state 無所事事中永遠運行,而我不知道為什么。 預期和期望的行為是在 function consume
完成后任務終止。
- - 編輯 - -
這是應用 user4815162342 給出的建議后的代碼
import asyncio
import uuid
async def consume(item):
print(f"Consuming {item}")
await asyncio.sleep(1)
print(f"{item} consumed")
async def hello(n):
print("Hello")
await asyncio.sleep(2)
print(f"Finishing hello {n}")
async def check_events(interval=1):
while True:
item = uuid.uuid4().hex
print(f"Producing item")
asyncio.create_task(consume(item))
print('Tasks count: ', len(asyncio.all_tasks()))
await asyncio.sleep(interval)
async def main():
await check_events()
if __name__ == "__main__":
asyncio.run(main())
事實證明,在每次 consume() 執行結束時,這些任務實際上都在消亡,但 PyCharm 圖形可視化工具並未反映這種行為。
您的隊列架構是非標准的,並沒有達到隊列的目的。 通常,隊列與固定數量的生產者和固定數量的消費者相關聯。 每個消費者在一個循環中獲取隊列項目,該循環要么是無限的,要么因取消或哨兵值而終止。 消費者通常按順序處理項目,這意味着他們使用await
而不是create_task
。 這可確保您具有與工作人員數量相匹配的並行性,並且項目以 FIFO 方式處理。
您的隊列有一個消費者,它會立即產生一個處理異步 function(您稱之為消費者),並且不會等待它。 在此設置中,您首先不需要隊列,您可以直接在生產者中調用asyncio.create_task(consume(...))
。 此外,如果您決定使用有界隊列來確保背壓,這將是無效的,因為create_task()
只是將工作推送到無界的異步內部隊列。
這工作得很好,但我的問題是,當看到並發圖時,消費第一個項目的任務在消費完成后並沒有死,所以這些任務在僵屍 state 中無所事事地運行,
與 POSIX 進程不同,asyncio 的任務沒有“僵屍狀態”的概念,因此您可能指的是在無限循環中從隊列中獲取項目的manage_events
協程 - 就像典型的消費者應該做的那樣。 要在所有項目完成后徹底終止它,您可以使用標記值,例如None
。 這意味着在producer
的末尾,您可以添加await q.put((None, None))
並在manage_events
中添加if item is None: break
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.