内容目录
asyncio并发编程¶
协程概念¶
1、协程的概念
在同一线程内,在执行一段代码过程中,可以中断并跳转至另一段代码中,接着之前中断的地方继续执行。协程运行状态与多线程类似,但是只有一个协程,不会像多线程一个任务对应一个线程
2、协程的优点
- 无需线程上下文切换,协程避免了无意义的调度,可以提高性能
- 无需原子操作锁定及同步开销
- 方便切换控制流,简化编程模型
- 高并发+高扩展性+低成本,一个CPU支持上万的协程不是问题,适合用于高并发处理
3、协程的缺点
- 无法利用多核资源。协程的本质是单线程,不能同时将单个CPU的多个核用上,协程需要进程配合才能运行在多CPU伤。
- 进行阻塞操作会阻塞掉整个程序
生成器的回顾¶
生成器有中断暂停的特点: 在运行第一个任务的时候遇到yield暂停并切换到另外一个任务上执行。
In [2]:
def func():
print('当前是一个生成器函数...')
while True:
yield '这是生成器函数返回的数据...'
#返回一个对象:生成器对象
obj = func()
# 生成器需要通过next方法进行驱动
print(next(obj))
# Python解释器遇到yield关键字会暂停,下次运行的时候接着上一次运行的位置继续运行
print(next(obj))
当前是一个生成器函数... 这是生成器函数返回的数据... 这是生成器函数返回的数据...
In [3]:
# 利用生成器特性进行任务切换
import time
def func_a():
while True:
print('这是func_a函数...')
yield
time.sleep(0.5)
def func_b(obj):
while True:
print('这是func_b函数...')
obj.__next__()
a = func_a()
b = func_b(a)
这是func_b函数... 这是func_a函数... 这是func_b函数... 这是func_a函数... 这是func_b函数... 这是func_a函数... 这是func_b函数... 这是func_a函数... 这是func_b函数... 这是func_a函数... 这是func_b函数... 这是func_a函数... 这是func_b函数... 这是func_a函数... 这是func_b函数... 这是func_a函数... 这是func_b函数... 这是func_a函数... 这是func_b函数...
--------------------------------------------------------------------------- KeyboardInterrupt Traceback (most recent call last) Cell In[3], line 16 13 obj.__next__() 15 a = func_a() ---> 16 b = func_b(a) Cell In[3], line 13, in func_b(obj) 11 while True: 12 print('这是func_b函数...') ---> 13 obj.__next__() Cell In[3], line 8, in func_a() 6 print('这是func_a函数...') 7 yield ----> 8 time.sleep(0.5) KeyboardInterrupt:
异步IO¶
In [11]:
# 同步IO的示例
import time
def func(i):
time.sleep(1)
print(i)
now = lambda: time.time()
start = now()
for i in range(5):
func(i)
print(f'同步所花费的时间:{now() - start} s ')
0 1 2 3 4 同步所花费的时间:5.022173166275024 s
In [16]:
# 异步IO的示例
import time
import asyncio
now = lambda: time.time()
start = now()
# 创建协程函数
async def func_asyn(i):
await asyncio.sleep(1)
print(i)
async def main():
tasks = [func_asyn(i) for i in range(5)]
await asyncio.gather(*tasks)
asyncio.run(main())
print(f'异步所花费的时间:{now() - start} s')
In [ ]:
# 在Pycharm中可以运行上述程序
# 异步所花费的时间:1.0020949840545654 s
asyncio的运行机制介绍¶
async的基本介绍¶
asyncio是Python3.4之后引入的标准库,内置对异步IO的支持。asyncio的编程模型是一个消息循环,我们从asyncio模块中直接获取一个EventLoop的引用,然后把需要执行的协程扔到EventLoop中执行,就实现了异步IO。
1、event_loop事件循环:
程序开启一个无限的循环,程序会把一些函数注册到事件循环上,当满足事件发生的时候,调用相应的协程函数。
2、coroutine协程:
协程对象,指一个使用async关键字定义的函数,它的调用不会立即执行函数,而是会返回一个协程对象。协程对象需要注册到事件循环,由事件循环调用。
3、task任务:
一个协程对象就是一个原生可以挂起的函数,任务则是对协程进一步封装,其中包含任务的各种状态。
4、future:
代表将来执行或者没有执行的任务的结果,它和task没有本质上的区别。
5、async/await关键字:
Python3.5用于定义协程的关键字,async定义一个协程,await用于挂起阻塞的异步调用接口。
In [24]:
# 事件循环的示例
import asyncio
# 协程任务1
async def work_func_1():
for _ in range(5):
print('我是协程任务1...')
await asyncio.sleep(1)
# 协程任务2
async def work_func_2():
for _ in range(5):
print('我是协程任务2...')
await asyncio.sleep(1)
async def main():
# 将当前的协程函数转为协程对象,并把多个协程对象添加到一个列表中
tasks = [
work_func_1(),
work_func_2()
]
# 使用asyncio.gather()并等待多个协程任务完成
await asyncio.gather(*tasks)
# 使用asyncio.run()运行异步程序
asyncio.run(main())
In [ ]:
运行结果:
我是协程任务1...
我是协程任务2...
我是协程任务1...
我是协程任务2...