几分钟弄懂python协程基础

3,596 阅读2分钟

协程是python避不开的基础,因为协程的存在,Python在执行效率上有了很大的提升。 协程的协字,带有协作的意思,假设在只有一个线程的情况下,我们想运行多个函数,正常的流程是一个挨着一个的运行,但是这样的效率未免太低了,举一个很简单的例子,假如有三个函数,第一个函数运行3分钟,第二个函数运行2分钟,第三个运行1分钟,那么运行下来需要6分钟,但是使用协程就只要3分钟就OK,因为取最大值就好,而不需要求和。假如这里的函数没有cpu密集计算的,而是一个只需要很小的计算资源,但是就是耗时,比如这样的例子很常见,比如网络请求,网络请求实际上我们在计算机本来需要运算的资源并不多,而大量的时间都处于等待,因此如果我们能够在等待的过程的空档期进行协作起来,就能使用这个线程计算其他的函数。我们可以看一个很简单例子:


import time
import asyncio

async def eat():
    await asyncio.sleep(3)
    print('吃饭')
async def sleep():
    await asyncio.sleep(2)
    print('睡觉')

async def dadoudou():
    await asyncio.sleep(1)
    print('打豆豆')

loop=asyncio.get_event_loop()
tasks=asyncio.gather(eat(),sleep(),dadoudou())
start=time.time()
loop.run_until_complete(tasks)
print('total spend time is {:.2f}s'.format(time.time()-start))
loop.close()

运行的结果如下:

打豆豆
睡觉
吃饭
total spend time is 3.00s

我们可以发现,我们程序只使用了3秒就结束了,而不是需要6秒,这就是协程的美妙的地方,具体是怎么运行的呢? 上面的程序我们使用了一个函数asyncio.gather(eat(),sleep(),dadoudou())将其包装起来,这函数不仅仅是包装,还好在内部进程任务调度,在调度的时候发现了三个awiat关键词,它就可以知道需要运行三个协程,就会自动进程分配,然后直到我们调用loop.run_until_complete(tasks),程序就直接进入运行状态了,而且会在同时运行这三个await,这样可以做到异步计算了。 这个例子很简单,我们可以看一个示例图:

image.png 我们可以看到使用协程只需要找到最大的计算时间的作为程序总的运行时间,而不使用协程就是求和,所以使用协程的3秒,不使用是6秒。

但是要注意的是,协程并不能提高cpu计算的效率,不论在io密集型还是cpu密集型,协程的本质是提高不了的,只是提高程序在等待的时间利用,而且相比线程来说,协程直接切换要快很多,不然这个玩意不如直接使用线程,线程在Python中切换效率很低,所以需要有协程这样一个东西来代替一些使用场景。