【问题标题】:How does the coroutine implement concurrency?协程如何实现并发?
【发布时间】:2018-01-01 06:17:04
【问题描述】:
#!/usr/bin/python3
# -*- coding: utf-8 -*-

import asyncio,time

async def asleep(n):
    time.sleep(n)   # blocking method


async def doAsync(n):                        
    print("doAsync{} start...".format(n))
    await asleep(2)                             # case 1    
    #await asyncio.gather(asleep(2))            # case 2
    print("doAsync{} end...".format(n))
    #...                                     

tasks = [doAsync(i) for i in range(1,4)]
tasks = [asyncio.ensure_future(t) for t in tasks]


if __name__ == "__main__":                  
    loop = asyncio.get_event_loop()         
    loop.run_until_complete(asyncio.wait(tasks))
    loop.close()                            

输出:

## case 1 output        # No concurrency runs
doAsync1 start...       
(wait 2 seconds)
doAsync1 end...
doAsync2 start...
(wait 2 seconds)
doAsync2 end...
doAsync3 start...
(wait 2 seconds)
doAsync3 end...

## case 2 output        # Concurrency runs
doAsync1 start...
doAsync2 start...
doAsync3 start...
(wait 2*3 seconds)      
doAsync1 end...
doAsync2 end...
doAsync3 end...

案例一:

虽然 sleep() 也是协程, 但是 doAsync 没有在“等待睡眠()”处挂起
doAsync 没有实现并发

案例2:

doAsync 是并发的

问题:

  1. 如何详细解释它的工作原理。
  2. 什么时候应该使用“await some_work()”,什么时候应该使用“await asyncio.gather(some_work)”

【问题讨论】:

    标签: python python-asyncio coroutine


    【解决方案1】:

    您提供的代码在这两种情况下都不是并发的。发生这种情况是因为这一行:

    async def asleep(n):
        time.sleep(n)   # blocking method
    

    time.sleep 冻结异步事件循环,使其无法处理其他同时运行的协程。在使用asyncio 时,你永远不应该这样做(如果你想在协程中运行一些阻塞代码,你应该使用loop.run_in_executor 在另一个线程中运行它,如here 所示)。

    为了让你的代码协程正常工作,你应该使用不阻塞事件循环的特殊 asyncio 版本的 sleep:

    async def asleep(n):
        await asyncio.sleep(n)   # blocking method
    

    比较执行此版本(在 case1 中)与您发布的版本(在 case1 中):6 秒与 2 秒。


    一旦我们使用 ensure_future 从协程创建 tasks,这些协程就会开始并发运行:

    tasks = [asyncio.ensure_future(c) for c in coros]  # this run all coroutines concurently
    

    使用asyncio.gather - 是同时运行协程的替代方法:

    await asyncio.gather(*coros)  # this run all coroutines concurently
    

    方式asyncio 的工作细节可能看起来相当复杂。我见过的最佳解释:David Beazley - Python Concurrency From the Ground Up。请注意,您通常无需了解底层细节即可在实践中使用asyncio。

    【讨论】:

    • 非常感谢我觉得我的问题可能不是并发和异步,而是协程的调度问题
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-03-27
    • 1970-01-01
    • 2022-11-14
    • 2012-10-29
    • 1970-01-01
    • 2010-09-12
    • 1970-01-01
    相关资源
    最近更新 更多