Python协程

python协程async和await

洗衣机例子

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import time


def washing1():
    time.sleep(3)  # 第一台洗衣机,
    print('washer1 finished')  # 洗完了


def washing2():
    time.sleep(8)
    print('washer2 finished')


def washing3():
    time.sleep(5)
    print('washer3 finished')


if __name__ == '__main__':
    start_time = time.time()
    washing1()
    washing2()
    washing3()
    end_time = time.time()
    print('总共耗时:{}'.format(end_time-start_time))

我们通过函数的方式调用,3个函数,总共耗时16 秒!

这里函数的执行方式是同步运行的,于是这里需要知道一个概念:

** 同步/异步 **

同步:在发出一个同步调用时,在没有得到结果之前,该调用就不返回。 异步:在发出一个异步调用后,调用者不会立刻得到结果,该调用就返回了。 再举个小学生在学校学习的一个案例: 小明同学的妈妈给他早上安排了三件事: 1.洗衣机洗衣服需要花 15 分钟, 2.电饭煲做饭需要花 20 分钟, 3.做作业需要花 25 分钟 那么请问:小明同学早上完成以上三件事需要花多久??? 这个大家肯定都知道是25分钟,因为在做作业的时候,可以先按下洗衣机和电饭煲的按钮,不用等它完成,洗衣机和电饭煲做好了会发出‘滴滴滴’的声音通知你。

所以这三件事是可以异步完成的,这就是异步的魅力!

多个任务执行 asyncio.create_task()

当我们需要3台洗衣机一起来工作,这时候需要创建多个任务,也就是会用到asyncio.create_task()

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import time
import asyncio


async def washing1():
    time.sleep(3)  # 第一台洗衣机,
    print('washer1 finished')  # 洗完了


async def washing2():
    time.sleep(8)
    print('washer2 finished')


async def washing3():
    time.sleep(5)
    print('washer3 finished')


async def main():
    print('start main:')
    start_time = time.time()
    task1 = asyncio.create_task(washing1())
    task2 = asyncio.create_task(washing2())
    task3 = asyncio.create_task(washing3())
    await task1
    await task2
    await task3
    end_time = time.time()
    print('-----------end main----------')
    print('总共耗时:{}'.format(end_time-start_time))


if __name__ == '__main__':
    # asyncio.run(main())
    loop = asyncio.get_event_loop()  # 创建一个事件循环
    result = loop.run_until_complete(main())  # 将协程对象加入到事件循环中,并执行

运行结果:

1
2
3
4
5
6
start main:
washer1 finished
washer2 finished
washer3 finished
-----------end main----------
总共耗时:16.000632286071777

await 使用

上面虽然异步执行了三个任务,但是时间并没减少,主要是因为 time.sleep() 是阻塞的,需换成异步的

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import time
import asyncio


async def washing1():
    await asyncio.sleep(3)  # 第一台洗衣机,
    print('washer1 finished')  # 洗完了


async def washing2():
    await asyncio.sleep(8)
    print('washer2 finished')


async def washing3():
    await asyncio.sleep(5)
    print('washer3 finished')

if __name__ == '__main__':
    print('start main:')
    start_time = time.time()
    # step1 创建一个事件循环
    loop = asyncio.get_event_loop()
    # step2 将异步函数(协程)加入事件队列
    tasks = [
        washing1(),
        washing2(),
        washing3()
    ]
    # step3 执行事件队列 直到最晚的一个事件被处理完毕后结束
    loop.run_until_complete(asyncio.wait(tasks))
    end_time = time.time()
    print('-----------end main----------')
    print('总共耗时:{}'.format(end_time-start_time))

这样就可以达到我们的预期,总共耗时是8秒了

1
2
3
4
5
6
start main:
washer1 finished
washer3 finished
washer2 finished
-----------end main----------
总共耗时:8.002010822296143
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import asyncio
import time


async def say_after(delay, what):
    await asyncio.sleep(delay)
    return f"{what} - {delay}"

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

    print(f"finished at {time.strftime('%X')}")

asyncio.run(main())

运行结果 started at 17:19:56 ['hello - 1', 'world - 2'] finished at 17:19:58

0%