【Python】 async/await
1. 前言
最近在使用的PTB的API,里面会碰到Python协程的使用,记录个人对此的浅显理解。
2. 进程、线程、协程
- 进程:由一个可执行程序以及该可执行程序执行过程中所需要的内存资源组成,每个进程有自己独立的内存管理,因此进程切换、通信需要消耗很大的资源。
- 线程:组成同进程一样,但是所占用的资源相比进程更少;线程为进程中一段程序执行流。
- 协程:微线程,所需的资源进一步减少。
- 进程和线程关系:进程为操作系统分配资源的最小单位,一个进程由一个或多个线程组成,对于一个进程中的多个线程,他们共享操作系统给该进程所分配内存资源。
3. Pyhton中协程实现
用到的关键字为async/await
,这两个关键字搭配使用。
async
声明一个函数为异步函数,异步函数的特点是在函数执行过程中遇到await
关键字则挂起,去执行其他异步函数。
await
用于暂定异步函数的执行(并发操作中,把程序控制器交给主程序,让其分配其他协程执行),其后面只能跟async
修饰的异步函数或带有__await__
属性的对象。
python
# This is a sample Python script.
import time
import asyncio
async def subtask(name,cost_time):
await asyncio.sleep(cost_time)
print('[{}] Current task is {}.'.format(time.time(), name))
async def task(name, cost_time):
print('[{}] {} is starting.'.format(time.time(), name))
time_start = time.time()
await subtask(name, cost_time)
time_end = time.time()
print('[{}] {} is ending.'.format(time.time(), name, time_end - time_start))
return '{} costs {}s'.format(name, time_end - time_start)
async def demo_1():
print('[{}] Demo1 starts tasks ......'.format(time.time()))
st = time.time()
result1 = await task('Task 1', 3)
result2 = await task('Task 2', 6)
result3 = await task('Task 3', 2)
et = time.time()
print('\b----- result ----')
print('Total task cost {}s.'.format(et - st))
print(result1)
print(result2)
print(result3)
print()
async def demo_2():
print('[{}] Demo2 starts tasks ......'.format(time.time()))
st = time.time()
result = await asyncio.gather(
task('Task 1', 3),
task('Task 2', 6),
task('Task 3', 2),
)
et = time.time()
print('\b----- result ----')
print('Total task cost {}s.'.format(et - st))
for item in result:
print(item)
print()
# Press the green button in the gutter to run the script.
if __name__ == '__main__':
asyncio.run(demo_1())
asyncio.run(demo_2())
运行结果:
text
[1709704883.4558887] Demo1 starts tasks ......
[1709704883.4558887] Task 1 is starting.
[1709704886.4710522] Current task is Task 1.
[1709704886.4710522] Task 1 is ending.
[1709704886.4710522] Task 2 is starting.
[1709704892.4716516] Current task is Task 2.
[1709704892.4716516] Task 2 is ending.
[1709704892.4716516] Task 3 is starting.
[1709704894.4731288] Current task is Task 3.
[1709704894.4731288] Task 3 is ending.
----- result ----
Total task cost 11.017240047454834s.
Task 1 costs 3.0151634216308594s
Task 2 costs 6.000599384307861s
Task 3 costs 2.0014772415161133s
[1709704894.475127] Demo2 starts tasks ......
[1709704894.475127] Task 1 is starting.
[1709704894.475127] Task 2 is starting.
[1709704894.475127] Task 3 is starting.
[1709704896.4786284] Current task is Task 3.
[1709704896.4786284] Task 3 is ending.
[1709704897.4788241] Current task is Task 1.
[1709704897.4788241] Task 1 is ending.
[1709704900.4797897] Current task is Task 2.
[1709704900.4797897] Task 2 is ending.
----- result ----
Total task cost 6.004662752151489s.
Task 1 costs 3.003697156906128s
Task 2 costs 6.004662752151489s
Task 3 costs 2.0035014152526855s
async
声明的函数为一部函数,其需要在时间循环中调用,若向普通函数调用异步函数,未能体现其异步特征,如同Demo_1。asyncio.run()
函数负责运行主体函数,并管理事件循环。asyncio.gather()
可以并发多个异步函数。调用Demo_2
,Task1、Task2、Task3同时执行,执行Task1的过程中遇到await
则挂起Task1,去执行Task2,Task2遇到await
则挂起,asyncio.gather()
会在3个任务之间进行调度。