Python 在列表中创建任务时的奇怪行为(异步IO) 导入异步IO 随机输入 异步def生成器(q:asyncio.Queue): 对于范围内的uu(100): 等待q.put(random.randint(1,10)) 异步def使用者(q:asyncio.Queue): 尽管如此: num=等待q.get() 打印(“从队列中获取:,num) q、 任务完成() 异步def main(): q=asyncio.Queue() pr=asyncio.create_任务(生产者(q)) consumers=[asyncio.create_任务(consumer(q))用于范围(10)] 等待公关 等待q.加入() 对于消费者中的c: c、 取消 asyncio.run(main())

Python 在列表中创建任务时的奇怪行为(异步IO) 导入异步IO 随机输入 异步def生成器(q:asyncio.Queue): 对于范围内的uu(100): 等待q.put(random.randint(1,10)) 异步def使用者(q:asyncio.Queue): 尽管如此: num=等待q.get() 打印(“从队列中获取:,num) q、 任务完成() 异步def main(): q=asyncio.Queue() pr=asyncio.create_任务(生产者(q)) consumers=[asyncio.create_任务(consumer(q))用于范围(10)] 等待公关 等待q.加入() 对于消费者中的c: c、 取消 asyncio.run(main()),python,python-asyncio,Python,Python Asyncio,我创建这个脚本是为了复制问题的简化版本。 所以这是一个非常基本的生产者-消费者类型的脚本,它工作得很好 但是,如果使用者内部发生异常,脚本将冻结。 例如,如果我这样修改使用者脚本: async def使用者(q:asyncio.Queue): 引发异常 尽管如此: num=等待q.get() 打印(“从队列中获取:,num) q、 任务完成() 当我现在运行脚本时,它会冻结,不会抛出异常。 但是,如果我将主脚本更改为在for循环中生成所有使用者任务,而不是通过如下列表理解生成它们: async

我创建这个脚本是为了复制问题的简化版本。 所以这是一个非常基本的生产者-消费者类型的脚本,它工作得很好 但是,如果使用者内部发生异常,脚本将冻结。 例如,如果我这样修改使用者脚本:

async def使用者(q:asyncio.Queue):
引发异常
尽管如此:
num=等待q.get()
打印(“从队列中获取:,num)
q、 任务完成()
当我现在运行脚本时,它会冻结,不会抛出异常。 但是,如果我将主脚本更改为在for循环中生成所有使用者任务,而不是通过如下列表理解生成它们:

async def main():
q=asyncio.Queue()
pr=asyncio.create_任务(生产者(q))
#consumers=[asyncio.create_任务(consumer(q))用于范围(10)]
对于范围(10)内的uu:
asyncio.create_任务(消费者(q))
等待公关
等待q.加入()
它抛出10个类型为Exception的异常,这是预期的行为。 我的两个问题是:

  • 为什么会发生这种奇怪的行为
  • 在我的实际脚本中,我想使用异常处理,所以我现在使用for循环方法。但是,在这种方法中,我没有对所有使用者任务的引用,因此我无法在需要时取消它们。我该怎么做?(创建后,只需将它们添加到列表中,即可复制原始问题) 我完全不知所措,感谢您的帮助
    我不认为使用列表理解而不是for循环对此有任何影响

    您应该在使用者中处理异常,并为每个
    get()
    调用
    task\u done()
    ,否则您将体验当前行为,其中
    q.join()
    将阻止/等待未完成的任务:

    如果join()当前处于阻塞状态,则当所有项都已被阻塞时,它将恢复 已处理(意味着每个 已放入()队列的项)

    test.py:

    import asyncio
    import random
    
    
    async def producer(q):
        for _ in range(10):
            await q.put(random.randint(1, 10))
    
    
    async def consumer(q):
        while True:
            num = await q.get()
    
            try:
                if num in (5, 8):
                    raise Exception("ERROR")
    
                print(f"Working on: {num}")
            except Exception as exc:
                print(f"{num}: {exc}")
            finally:
                q.task_done()
    
    
    async def main():
        q = asyncio.Queue()
    
        pr = asyncio.create_task(producer(q))
    
        tasks = []
    
        for _ in range(10):
            tasks.append(asyncio.create_task(consumer(q)))
    
        await pr
        await q.join()
    
        for task in tasks:
            task.cancel()
    
        await asyncio.gather(*tasks, return_exceptions=True)
    
    
    if __name__ == "__main__":
        asyncio.run(main())
    
    $ python test.py
    Working on: 7
    Working on: 4
    Working on: 4
    Working on: 4
    Working on: 1
    Working on: 3
    8: ERROR
    Working on: 6
    5: ERROR
    Working on: 4
    
    测试:

    import asyncio
    import random
    
    
    async def producer(q):
        for _ in range(10):
            await q.put(random.randint(1, 10))
    
    
    async def consumer(q):
        while True:
            num = await q.get()
    
            try:
                if num in (5, 8):
                    raise Exception("ERROR")
    
                print(f"Working on: {num}")
            except Exception as exc:
                print(f"{num}: {exc}")
            finally:
                q.task_done()
    
    
    async def main():
        q = asyncio.Queue()
    
        pr = asyncio.create_task(producer(q))
    
        tasks = []
    
        for _ in range(10):
            tasks.append(asyncio.create_task(consumer(q)))
    
        await pr
        await q.join()
    
        for task in tasks:
            task.cancel()
    
        await asyncio.gather(*tasks, return_exceptions=True)
    
    
    if __name__ == "__main__":
        asyncio.run(main())
    
    $ python test.py
    Working on: 7
    Working on: 4
    Working on: 4
    Working on: 4
    Working on: 1
    Working on: 3
    8: ERROR
    Working on: 6
    5: ERROR
    Working on: 4