1.事件循环
可以理解成为一个死循环,去检查任务列表中的任务,如果可执行就去执行,如果检查不到就是不可执行的,那就忽略掉去执行其他可执行的任务,如果IO结束了(比如说去百度下载图片,下载完了就会变成可执行任务)再去执行下载完成之后的逻辑
1
2
3
4
5
6
7
8
9
|
#这里的任务是有状态的,比如这个任务已经完成或者正在执行或者正在IO等待
任务列表 = [ 任务 1 , 任务 2 , 任务 3 ,... ]
while True :
可执行的任务列表,已完成的任务列表 = 去任务列表中检查所有的任务,将 '可执行' 和 '已完成' 的任务返回
for 就绪任务 in 可执行的任务列表:
执行已就绪的任务
for 已完成的任务 in 已完成的任务列表:
在任务列表中移除 已完成的任务
如果 任务列表 中的任务都已完成,则终止循环
|
1
2
3
4
5
|
#在编写程序时候可以通过如下代码来获取和创建事件循环。
import asyncio
loop = asyncio.get_event_loop()
#将任务放到任务列表,让事件循环去检测任务的状态(是否可运行,是否IO)
loop.loop.run_until_complete(任务)
|
2.协程和异步编程
协程函数,定义形式为 async def 的函数。
协程对象,调用 协程函数() 所返回的对象。
1
2
3
4
5
|
# 定义一个协程函数
async def func():
pass
# 调用协程函数,返回一个协程对象(内部代码不会执行)
result = func()
|
2.1 基本使用
程序中,如果想要执行协程函数的内部代码,需要 事件循环 和 协程对象 配合才能实现
示例1:
1
2
3
4
5
6
7
8
9
10
11
12
|
import asyncio
async def func():
print ( "协程内部代码" )
# 调用协程函数,返回一个协程对象。
result = func()
# 方式一
# loop = asyncio.get_event_loop() # 创建一个事件循环
# loop.run_until_complete(result) # 将协程当做任务提交到事件循环的任务列表中,协程执行完成之后终止。
# 方式二
# 本质上方式一是一样的,内部先 创建事件循环 然后执行 run_until_complete,一个简便的写法。
# asyncio.run 函数在 Python 3.7 中加入 asyncio 模块,
asyncio.run(result)
|
2.2 await
await+可等待对象(协程对象,Future,Task对象)
await是一个只能在协程函数中使用的关键字,用于遇到IO操作时挂起 当前协程(任务),当前协程(任务)挂起过程中 事件循环可以去执行其他的协程(任务),当前协程IO处理完成时,可以再次切换回来执行await之后的代码。
1
2
3
4
5
6
7
8
9
10
|
import asyncio
async def func():
print ( "执行协程函数内部代码" )
# 遇到IO操作挂起当前协程(任务),等IO操作完成之后再继续往下执行。
# 当前协程挂起时,事件循环可以去执行其他协程(任务)。
#response是IO耗时结束后拿到的结果
response = await asyncio.sleep( 2 )
print ( "IO请求结束,结果为:" , response)
result = func()
asyncio.run(result)
|
结果
执行协程函数内部代码
IO请求结束,结果为: None
#这里返回None表示这个好事没有啥意义,如果你是下载了一张图片成功后会返回一个结果
示例2:
1
2
3
4
5
6
7
8
9
10
11
12
|
import asyncio
async def others():
print ( "start" )
await asyncio.sleep( 2 )
print ( 'end' )
return '返回值'
async def func():
print ( "执行协程函数内部代码" )
# 遇到IO操作挂起当前协程(任务),等IO操作完成之后再继续往下执行。当前协程挂起时,事件循环可以去执行其他协程(任务)。
response = await others()
print ( "IO请求结束,结果为:" , response)
asyncio.run( func() )
|
执行结果:
执行协程函数内部代码
start
end
IO请求结束,结果为: 返回值
示例3:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
import asyncio
async def others():
print ( "start" )
await asyncio.sleep( 2 )
print ( 'end' )
return '返回值'
async def func():
print ( "执行协程函数内部代码" )
# 遇到IO操作挂起当前协程(任务),等IO操作完成之后再继续往下执行。当前协程挂起时,事件循环可以去执行其他协程(任务)。
#await等待有返回值才会向下执行
response1 = await others()
print ( "IO请求结束,结果为:" , response1)
response2 = await others()
print ( "IO请求结束,结果为:" , response2)
asyncio.run( func() )
|
执行结果:
执行协程函数内部代码
start
end
IO请求结束,结果为: 返回值
start
end
IO请求结束,结果为: 返回值
下一步依赖上一步的结果时使用await,但如果有其他任务依然会切换到其他任务去执行
2.3 Task对象
在事件循环中添加多个任务。
Tasks用于并发调度协程,通过asyncio.create_task(协程对象)的方式创建Task对象,这样可以让协程加入事件循环中等待被调度执行。
除了使用 asyncio.create_task() 函数以外,还可以用低层级的 loop.create_task() 或 ensure_future() 函数。
不建议手动实例化 Task 对象。
本质上是将协程对象封装成task对象,并将协程立即加入事件循环,同时追踪协程的状态。
注意:asyncio.create_task() 函数在 Python 3.7 中被加入。
在 Python 3.7 之前,可以改用低层级的 asyncio.ensure_future() 函数。
示例1:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
import asyncio
async def func():
print ( 1 )
await asyncio.sleep( 2 )
print ( 2 )
return "返回值"
async def main():
print ( "main开始" )
# 创建协程,将协程封装到一个Task对象中并立即添加到事件循环的任务列表中,等待事件循环去执行(默认是就绪状态)。
task1 = asyncio.create_task(func())
# 创建协程,将协程封装到一个Task对象中并立即添加到事件循环的任务列表中,等待事件循环去执行(默认是就绪状态)。
task2 = asyncio.create_task(func())
print ( "main结束" )
# 当执行某协程遇到IO操作时,会自动化切换执行其他任务。
# 此处的await是等待相对应的协程全都执行完毕并获取结果
ret1 = await task1
ret2 = await task2
print (ret1, ret2)
asyncio.run(main())
|
执行结果:
main开始
main结束
1
1
2
2
返回值 返回值
实例2:
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 asyncio
async def func():
print ( 1 )
await asyncio.sleep( 2 )
print ( 2 )
return "返回值"
async def main():
print ( "main开始" )
# 创建协程,将协程封装到Task对象中并添加到事件循环的任务列表中,等待事件循环去执行(默认是就绪状态)。
# 在调用
task_list = [
asyncio.create_task(func(), name = "n1" ),
asyncio.create_task(func(), name = "n2" )
]
print ( "main结束" )
# 当执行某协程遇到IO操作时,会自动化切换执行其他任务。
# 此处的await是等待所有协程执行完毕,并将所有协程的返回值保存到done
# 如果设置了timeout值,则意味着此处最多等待的秒,完成的协程返回值写入到done中,未完成则写到pending中(比如下面的Timeout=1,要下载的图片是两秒,设为1秒就会执行失败,done内为空,而pending中就是执行失败的)。
done, pending = await asyncio.wait(task_list, timeout = None )
print (done, pending)
asyncio.run(main())
执行结果:
main开始
main结束
1
1
2
2
{
<Task finished name = 'n1' coro = <func() done, defined at C: / Users / xuan.li / Desktop / unidevopss / py3x64 / ibuildmaster / apps / PROD / tests.py: 513 > result = '返回值' >,
<Task finished name = 'n2' coro = <func() done, defined at C: / Users / xuan.li / Desktop / unidevopss / py3x64 / ibuildmaster / apps / PROD / tests.py: 513 > result = '返回值' >
}
set ()
|
示例3:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
import asyncio
async def func():
print ( "执行协程函数内部代码" )
# 遇到IO操作挂起当前协程(任务),等IO操作完成之后再继续往下执行。当前协程挂起时,事件循环可以去执行其他协程(任务)。
response = await asyncio.sleep( 2 )
print ( "IO请求结束,结果为:" , response)
coroutine_list = [func(), func()]
# 错误:coroutine_list = [ asyncio.create_task(func()), asyncio.create_task(func()) ]
# 此处不能直接 asyncio.create_task,因为将Task立即加入到事件循环的任务列表,
# 但此时事件循环还未创建,所以会报错。
# 使用asyncio.wait将列表封装为一个协程,并调用asyncio.run实现执行两个协程
# asyncio.wait内部会对列表中的每个协程执行ensure_future,封装为Task对象。
done,pending = asyncio.run( asyncio.wait(coroutine_list) )
|
以上就是Python协程asyncio 异步编程笔记分享的详细内容,更多关于Python协程asyncio 异步编程的资料请关注服务器之家其它相关文章!
原文链接:https://blog.csdn.net/weixin_47906106/article/details/120249639