asyncio 简单使用
- Python3版本的新特性, 本质上是协程
- 异步IO采用消息循环的模式, 重复
读取消息--处理消息
的过程 - 也就是说异步IO模型 需要一个消息循环,在消息循环中,主线程不断地重复 “读取消息--处理消息”这一过程
关键字
- async : 定义一个协程
- await : 用于挂起阻塞的异步调用接口(IO)
await作用:控制运行流程,按顺序执行,即等待该函数运行完成,再继续往后执行
ps : python 3.5中对原本协程方式做了改变
# 原本协程@asyncio.coroutine装饰,使用yield from来驱动(后面演示)
@asyncio.coroutine ---> async
yield from ---> await
测试 :
- 未添加asyncio
import time
def hello():
time.sleep(1)
def run():
for i in range(5):
hello()
print('Hello World:%s' % time.time())
if __name__ == '__main__':
run()
'''
Hello World:1627525626.5793433
Hello World:1627525627.579919
Hello World:1627525628.581251
Hello World:1627525629.5832856
Hello World:1627525630.5842235
'''
- 添加asyncio
import time
import asyncio
# 定义异步函数
async def hello():
print('Hello World:%s' % time.time())
# 必须使用await,不能使用yield from;如果是使用yield from ,需要采用@asyncio.coroutine相对应
await asyncio.sleep(1)
print('Hello wow World:%s' % time.time())
def run():
tasks = []
for i in range(5):
tasks.append(hello())
loop.run_until_complete(asyncio.wait(tasks))
loop = asyncio.get_event_loop()
if __name__ == '__main__':
run()
'''
Hello World:1627525656.033751
Hello World:1627525656.0337813
Hello World:1627525656.0337918
Hello World:1627525656.0338
Hello World:1627525656.033807
(约1s)
Hello wow World:1627525657.035745
Hello wow World:1627525657.0357795
Hello wow World:1627525657.0357869
Hello wow World:1627525657.0357919
Hello wow World:1627525657.0357978
'''
- 用法2(3.7版本的写法)
import time
import asyncio
async def task():
await asyncio.sleep(3)
async def main():
task_list = []
for i in range(5):
task_list.append(task())
await asyncio.gather(*task_list)
if __name__ == '__main__':
start_time = time.time()
asyncio.run(task())
print(f"用时:{time.time() - start_time} s")
事件循环 Eventloop 的使用
- Eventloop 是asyncio应用的核心,把一些异步函数注册到这个事件循环上
- 事件循环会循环执行这些函数,当执行到某个函数时,如果它正在等待I/O返回,如它正在进行网络请求,或者sleep操作,事件循环会暂停它的执行去执行其他的函数
- 当某个函数完成I/O后会恢复,下次循环到它的时候继续执行
- 因此,这些异步函数可以协同(Cooperative)运行:这就是事件循环的目标
示例 :
- 原来装饰器的写法
import asyncio
@asyncio.coroutine
def hello():
print("Hello world!")
# 异步调用asyncio.sleep(2):
yield from asyncio.sleep(2)
print("Hello again!")
# 获取EventLoop:
loop = asyncio.get_event_loop()
# 执行coroutine
loop.run_until_complete(hello())
loop.close()
- task封装多个协程任务
import threading
import asyncio
@asyncio.coroutine
def hello():
print('Hello world! (%s)' % threading.currentThread())
yield from asyncio.sleep(2)
print('Hello again! (%s)' % threading.currentThread())
loop = asyncio.get_event_loop()
tasks = [hello(), hello(),hello()]
# loop.run_until_complete(asyncio.wait(tasks))
loop.run_until_complete(asyncio.gather(*tasks)) # *号打散的方式
loop.close()
'''
Hello world! (<_MainThread(MainThread, started 140426122789376)>)
Hello world! (<_MainThread(MainThread, started 140426122789376)>)
Hello world! (<_MainThread(MainThread, started 140426122789376)>)
(约2s)
Hello again! (<_MainThread(MainThread, started 140426122789376)>)
Hello again! (<_MainThread(MainThread, started 140426122789376)>)
Hello again! (<_MainThread(MainThread, started 140426122789376)>)
'''