【问题标题】:How to combine sync object iteration and async code in python?如何在python中结合同步对象迭代​​和异步代码?
【发布时间】:2017-12-08 01:54:57
【问题描述】:

我有一个对象列表,对于每个对象,我需要对其进行一些异步工作。我不确定我是否正确构建它:

def run(tasks):
    async def async_wrapper():
        async def update_task():
            updated_task = await task_manager.async_get_task_status(session, task)
            # do some works with updated_task

        workers = []
        resolver = aiohttp.AsyncResolver()
        connector = aiohttp.TCPConnector(resolver=resolver, family=socket.AF_INET)
        async with aiohttp.ClientSession(connector=connector) as session:
            for local_task in tasks: # tasks is a list of object
                await update_ocr_task()

    loop = asyncio.get_event_loop()
    loop.run_until_complete(aysnc_wrapper())

我认为 for 循环是同步的,会完全阻止进度,对吗?如果是,如何构造?

【问题讨论】:

    标签: python python-asyncio aiohttp


    【解决方案1】:
    def run(tasks):
        # ...
    
        loop = asyncio.get_event_loop()
        loop.run_until_complete(aysnc_wrapper())
    

    通常这不是人们编写异步程序的方式:事件循环应该是全局的,并作为整个脚本的主要入口点启动。像你一样(在单个函数run 中运行事件循环)使得上层代码无法在同一个事件循环中运行其他协程。

    如果您理解这一点并且您想要的只是阻止无法与其他异步内容一起使用的 run 函数,请进一步阅读。


    您的 async_wrapper 的问题是它仅在前一个完成后才等待下一个 update_ocr_task() 协程。 For 循环不是我们所说的“阻塞”,它只是不是并发的——它没有利用异步范式提供的好处。

    要获得使用 asyncio 的好处,您应该同时运行多个协程。常用的方法是使用asyncio.gather():

    async def async_wrapper():
    
        async def process_single_task(task):
            resolver = aiohttp.AsyncResolver()
            connector = aiohttp.TCPConnector(resolver=resolver, family=socket.AF_INET)
            async with aiohttp.ClientSession(connector=connector) as session:
                await session.get(...) # do all job for *single* local task here.
    
        # Run multiple task processing coroutines concurrently:
        await asyncio.gather(
            *[process_single_task(t) for t in tasks]
        )
    

    如果你愿意,你也可以阅读 this 关于 asyncio 的小回答。

    【讨论】:

    • 哦,我想我已经注意到出了什么问题。 await update_ocr_task() 与其他协程(例如 await task_manager.async_get_task_status(session, task))并发,但不是自身。 gather 使所有 update_ocr_task 并发。这就是我想说的。顺便说一句,我将整个循环包装成一个函数的原因是我想在一个单独的线程/进程中运行异步事件循环,因为我的主线程是一个同步任务。
    • 一个小问题,我可以用async for 替换for 来完成同样的行为吗?
    • @Sraw 没有。 async for 用于通过异步生成器进行迭代。这是完全不同的事情。
    • 谢谢你的回答,我对协程了解多了。
    猜你喜欢
    • 2015-09-22
    • 1970-01-01
    • 2018-05-23
    • 1970-01-01
    • 2021-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-04
    相关资源
    最近更新 更多