async/await的使用 同步和异步协程的比较 假设有三个任务,里面都有大量的i/o等待时间 同步
import datetime
import time
def test1():
time.sleep(3)
print('washing1 finished')
def test2():
time.sleep(2)
print('washing2 finshed')
def test3():
time.sleep(5)
print('washing3 finshed')
if __name__ == '__main__':
time1 = datetime.datetime.now()
test1()
test2()
test3()
time2 = datetime.datetime.now()
print(time2-time1)
washing1 finished
washing2 finshed
washing3 finshed
0:00:10.001583
协程
import asyncio
import datetime
async def test1():
await asyncio.sleep(3)
print('washer1 finished')
async def test2():
await asyncio.sleep(2)
print('washer2 finished')
async def test3():
await asyncio.sleep(5)
print('washer3 finished')
if __name__ == '__main__':
"""
事件循环机制分为以下几步骤:
1. 创建一个事件循环
2. 将异步函数加入事件队列
3. 执行事件队列, 直到最晚的一个事件被处理完毕后结束
4. 最后建议用 close() 方法关闭事件循环, 以彻底清理 loop 对象防止误用
"""
time1 = datetime.datetime.now()
loop = asyncio.get_event_loop()
tasks = [
test1(),
test2(),
test3(),
]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()
time2 = datetime.datetime.now()
print(time2-time1)
python3.7 python3.7不需要我们手动创建事件循环,它会自动帮我们创建
相当于同步,只能说明基础语法
import asyncio, datetime
async def func1(name):
print(name, "启动")
await asyncio.sleep(2)
print(name, "关闭")
async def main():
await func1("动作1")
await func1("动作2")
await func1("动作3")
if __name__ == '__main__':
time1 = datetime.datetime.now()
asyncio.run(main())
time2 = datetime.datetime.now()
print(time2-time1)
"""
动作1 启动
动作1 关闭
动作2 启动
动作2 关闭
动作3 启动
动作3 关闭
"""
import asyncio
import datetime
async def func1(name):
print(name, "启动")
await asyncio.sleep(2)
print(name, "关闭")
async def main():
await asyncio.gather(
asyncio.create_task(func1("动作1")),
asyncio.create_task(func1("动作2")),
asyncio.create_task(func1("动作3")),
)
if __name__ == '__main__':
time1 = datetime.datetime.now()
asyncio.run(main())
time2 = datetime.datetime.now()
print(time2-time1)
"""
动作1 启动
动作2 启动
动作3 启动
动作1 关闭
动作2 关闭
动作3 关闭
"""
异步函数调用异步函数
import asyncio
import datetime
async def func2(name):
await asyncio.sleep(2)
print(name, "我是func2")
async def func1(name):
print(name, "启动")
await func2(name)
print(name, "关闭")
async def main():
await asyncio.gather(
asyncio.create_task(func1("动作1")),
asyncio.create_task(func1("动作2")),
asyncio.create_task(func1("动作3")),
)
if __name__ == '__main__':
time1 = datetime.datetime.now()
asyncio.run(main())
time2 = datetime.datetime.now()
print(time2-time1)
"""
动作1 启动
动作2 启动
动作3 启动
动作1 我是func2
动作1 关闭
动作2 我是func2
动作2 关闭
动作3 我是func2
动作3 关闭
"""
两个异步程序async a、async b:
a中一步有await,当程序碰到关键字await b后; 异步程序a挂起,去执行异步b程序(就相当于从一个函数内部跳出去执行其他函数); 当挂起条件结束时候,不管b是否执行完,要马上从b程序中跳出来,回到原程序a执行原来的操作; 如果await后面跟的b函数不是异步函数,那么操作就只能等b执行完再返回,无法在b执行的过程中返回,这样就相当于直接调用b函数,没必要使用await关键字了。
因此,需要await后面跟的是异步函数。
实际上这样我们会发现有点不合理,因为实际上我们日常中比如有两台洗衣机,往往是这台开机洗衣之后就去操作另一台洗衣机的。这样就不用一直等待一个洗衣机洗完之后才去操作第二台洗衣机。为了提高效率,这里使用携程,“并发的”洗衣服。
import time
async def washing1():
time.sleep(3)
print('小朋友的衣服洗完了')
async def washing2():
time.sleep(2)
print('爷爷奶奶的衣服洗完了')
async def washing3():
time.sleep(5)
print('爸爸妈妈的衣服洗完了')
startTime = time.time()
washing1()
washing2()
washing3()
endTime = time.time()
print("洗完三批衣服共耗时: ",endTime-startTime)
其实上面的脚本是无法运行的。 从正常人的理解来看, 我们现在有了异步函数, 但是却忘了定义应该什么时候 “离开” 一台洗衣机, 去看看另一个… 这就会导致, 现在的情况是我们一边看着第一台洗衣机, 一边着急地想着"是不是该去开第二台洗衣机了呢?" 但又不敢去 (只是打个比方), 最终还是花了10秒的时间才把衣服洗完.
参考前言1.2中介绍的函数是要被指定为可中断的,且中断的函数中需要指定为可等待的。现在我们吸取了上次的教训, 告诉自己洗衣服的过程是 “可等待的” (awaitable), 在它开始洗衣服 的时候, 我们可以去弄别的机器.
|