簡體   English   中英

生產者-消費者,一個生產者和多個消費者

[英]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.

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