浅析Python中的asyncio

asyncio理解

最近突然想了解一下Python的异步编程,于是乎就去了解了下asyncio的使用。借用官网的话

成都创新互联是一家集网站建设,秦皇岛企业网站建设,秦皇岛品牌网站建设,网站定制,秦皇岛网站建设报价,网络营销,网络优化,秦皇岛网站推广为一体的创新建站企业,帮助传统企业提升企业形象加强企业竞争力。可充分满足这一群体相比中小企业更为丰富、高端、多元的互联网需求。同时我们时刻保持专业、时尚、前沿,时刻以成就客户成长自我,坚持不断学习、思考、沉淀、净化自己,让我们为更多的企业打造出实用型网站。

asyncio 是用来编写并发代码的库,使用 async/await 语法。其用作多个提供高性能 Python 异步框架的基础,包括网络和网站服务,数据库连接库,分布式任务队列等等。

要理解Python的异步编程方式这里我直接上例子

import asyncio

async def main():
    print('Hello ...')
    await asyncio.sleep(1)
    print('... World!')

main()

运行结果

RuntimeWarning: coroutine 'main' was never awaited

可以看到对于加了async的方法直接调用是无法运行出结果的,这是因为async修饰的函数其运行的返回结果是一个coroutine对象,而coroutine对象需要放到Event Loop中才能执行。

所以我们把上述代码改成

async def main():
    print('Hello ...')
    await asyncio.sleep(1)
    print('... World!')

asyncio.run(main())

运行结果

Hello ...
... World!

这样我们就解决了coroutine的运行问题。下面我们再来尝试实现一下异步程序,看代码

import asyncio
import time

async def say_after(delay, what):
    await asyncio.sleep(delay)
    print(what)

async def main():
    print(f"started at {time.strftime('%X')}")
    await say_after(1, 'hello')
    await say_after(2, 'world')
    print(f"finished at {time.strftime('%X')}")

asyncio.run(main())

运行结果按道理应该是间隔了3s,可是结果如下

started at 14:07:43
hello
world
finished at 14:07:46

这是为什么呢?查阅一番资料发现Python中的异步执行模式依赖于Event Loop,在等待的间隙中需要从Event Loop中找其它可以运行的程序,await关键字就是将coroutine转化成一个task加入到Event Loop中去,而执行第一个say_after的时候,第二个say_after并没有加入到Event Loop中去,所以在第一个say_after等待的时候无法去执行第二个say_after,最终导致的结果就是程序运行了3s,并没有达到异步的效果。

有两种方式解决这个问题

1、提前将两个say_after加入到eventloop中

async def main():
    task1 = asyncio.create_task(say_after(1, 'hello'))
    task2 = asyncio.create_task(say_after(2, 'world'))
    print(f"started at {time.strftime('%X')}")
    await task1
    await task2
    print(f"finished at {time.strftime('%X')}")

2、使用gather方法

async def main():
    print(f"started at {time.strftime('%X')}")
    await asyncio.gather(
        say_after(1, 'hello'),
        say_after(2, 'world')
    )
    print(f"finished at {time.strftime('%X')}")

最后二者的运行结果都是间隔了2s

started at 14:17:43
hello
world
finished at 14:17:45

最后,需要提醒的是,对于Python的asyncio来说,无论何时都只有1条语句运行在cpu上,所以如果我们的程序没有等待的时候,asyncio其实并没有什么帮助。

参考资料

Python官方文档
B站大佬讲解


文章标题:浅析Python中的asyncio
文章起源:http://hbruida.cn/article/dsogjpo.html