如何在python中组合同步对象迭代​​和异步代码?

时间:2017-12-08 01:54:58

标签: python python-asyncio aiohttp

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

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循环是同步的,会完全阻止进度,对吗?如果我是,如何构建它?

1 个答案:

答案 0 :(得分:3)

def run(tasks):
    # ...

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

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

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

async_wrapper的问题在于,只有在完成上一个update_ocr_task()后才会等待下一个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] ) 协程。 for循环不是我们所说的“阻塞”,但它不是并发的 - 它不使用异步范例提供的好处。

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

function stableSort(arr, compare) {
    var original = arr.slice(0);

    arr.sort(function(a, b){
        var result = compare(a, b);
        return result === 0 ? original.indexOf(a) - original.indexOf(b) : result;
    });

    return arr;
}

如果您还想要,也可以阅读this关于asyncio的一般答案。