协程如何实现并发?

时间:2018-01-01 06:17:04

标签: python python-asyncio coroutine

#!/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...

案例1:

虽然睡着了()也是一个协程, 但是doAsync并未等待#34;等待asleep()"
doAsync不实现并发

案例2:

doAsync是并发的

问题:

  1. 如何解释它的工作原理细节。
  2. 我应该何时使用"等待some_work()"我何时应该使用"等待asyncio.gather(some_work)"

1 个答案:

答案 0 :(得分:0)

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

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

time.sleep冻结asyncio事件循环,使其无法处理其他正在运行的同时协同程序。在使用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的低级细节。