Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/333.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 一个生产者和多个消费者的生产者-消费者_Python_Python 3.x_Async Await_Python Asyncio - Fatal编程技术网

Python 一个生产者和多个消费者的生产者-消费者

Python 一个生产者和多个消费者的生产者-消费者,python,python-3.x,async-await,python-asyncio,Python,Python 3.x,Async Await,Python Asyncio,我试图通过使用asyncio实现生产者-消费者模型,该模型允许生产者将n项放入队列,然后创建n消费者,以并发方式处理n项 这是我迄今为止的尝试: 导入异步IO 导入uuid 导入时间 随机输入 异步def生成(q,间隔=1): 尽管如此: n=random.randint(0,20) 对于范围内的u(n): 等待q.put((uuid.uuid4().hex,time.perf_counter()) 等待异步睡眠(间隔) 异步def消耗(项目,t): 打印(f“管理{item}…”) 等待asy

我试图通过使用asyncio实现生产者-消费者模型,该模型允许生产者将
n
项放入队列,然后创建
n
消费者,以并发方式处理
n

这是我迄今为止的尝试:

导入异步IO
导入uuid
导入时间
随机输入
异步def生成(q,间隔=1):
尽管如此:
n=random.randint(0,20)
对于范围内的u(n):
等待q.put((uuid.uuid4().hex,time.perf_counter())
等待异步睡眠(间隔)
异步def消耗(项目,t):
打印(f“管理{item}…”)
等待asyncio.sleep(1)
打印(f“在{time.time()-t:.2f}s之后管理的项”)
异步def管理_事件(q):
尽管如此:
item,t=wait q.get()
打印(f“使用队列中的{item}.In:{time.perf_counter()-t}”)
task=asyncio.create_任务(消费(item,time.time()),name=str(item))
打印(“管理项目后”)
异步def main():
q=asyncio.Queue()
等待asyncio.gather(生成(q,2),管理_事件(q))
如果名称=“\uuuuu main\uuuuuuuu”:
s=时间。性能计数器()
asyncio.run(main())
已用时间=时间。性能计数器()-s
打印(f“{uuuu文件{uuuu}在{0.2f}秒内执行”)
每隔
时间间隔
秒,将创建0到20个项目并将其放入队列
q
。在函数
manage_events
中,每次从队列中提取项目时,都会创建一个异步任务以使用该项目

这工作得很好,但我的问题是,当看到并发关系图时,消耗第一个项目的任务在消耗完成后不会消亡,因此这些任务永远处于僵尸状态,什么也不做,我不知道为什么。预期和期望的行为是,在函数
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 graph visualizer并不反映这种行为。

您的队列体系结构是非标准的,无法达到队列的目的。通常,队列与固定数量的生产者和固定数量的消费者相关联。每个使用者在一个循环中获取队列项目,该循环是无限的,或者通过取消或哨兵值终止。消费者通常按顺序处理项目,这意味着他们使用
等待
而不是
创建任务
。这确保了并行性与工作进程的数量相匹配,并且项目以FIFO方式处理

您的队列只有一个使用者,它可以立即生成一个处理异步函数(您称之为使用者),并且不等待它。在这个设置中,您首先不需要队列,您可以直接在producer中调用
asyncio.create_task(consume(…)
。此外,如果您决定使用有界队列来确保背压,那么它将无效,因为
create_task()
只是将工作推送到asyncio的无界内部队列

这工作得很好,但我的问题是,当看到并发图时,消耗第一个项目的任务在消耗完成后不会消亡,因此这些任务永远在僵尸状态下运行,什么也不做


与POSIX进程不同,asyncio的任务没有“僵尸状态”的概念,因此您可能指的是
manage_events
corroutine,它以无限循环的方式从队列中获取项目,这与典型的消费者应该做的很像。要在完成所有项目后干净地终止它,可以使用sentinel值,例如
None
。这意味着在
producer
的末尾,您可以添加
wait q.put((无,无))
并在
manage_events
中,如果项目为None:break,您可以放置
,谢谢您的时间。也许我应该更好地解释算法的目的。创建队列中的项目时,我需要尽可能快地处理它们。由于所消费物品的性质,此过程可能需要数秒到数小时。如果遇到需要几个小时才能处理的项目,我希望使用asyncio提供的并发性来处理队列中的新项目。我有一个线程版本的算法运行得很好,我只是在探索另一个选项。@AlanWik这是有意义的,但是你根本不需要队列-正如我提到的,你可以在producer中调用
create\u task(consume(…)
)。(在asyncio中创建任务很便宜,这一点您已经知道,因为您已经在
manage_events()
中为每个项目创建了任务。)并且摆脱队列将消除
manage_events
仍然挂起的问题。我遗漏了什么吗?我看到了您删除队列的方法,而且确实更简单,效果也很好。我使用PyCharm作为IDE,它有一个观察异步IO并发图的选项。我所观察到的是,一旦项目已经被处理,创建的每个任务仍然是活动的。这是正常的行为吗?在线程版本中,一旦任务完成并且consume()函数的执行完成,线程就会死亡。好的,在一些测试之后。我发现PyCharm的asyncio图形查看器有漏洞。通过打印任务的数量,我得出结论,一旦通过
create\u task(foo())
执行的函数完成,该任务将被标记为已完成并有效地终止。再次感谢您的时间,我将您的答案标记为所给提示的解决方案。@AlanWik这不正常-当一个协同程序返回时,任务也应该完成。这种情况是发生在玩具版本的代码中,还是发生在实际工作的版本中?艾尔