协程
协程(Coroutine)不是计算机提供,程序员人为创造
协程也可以称为微线程, 是一种用户态的上下文切换技术。就是通过一个线程实现代码块相互切换执行。
实现协程方法:
- greenlet
- yield
- asyncio 装饰器
- async/await 关键字
greenlet
pip install greenlet
from greenlet import greenlet
def func1():
print(1) # 2. 输出 1
gr2.switch() # 3. 切换到 func2 函数
print(2) # 6. 输出 2
gr2.switch() # 7. 切换到 func2 函数,从上一次执行位置向后执行
def func2():
print(3) # 4. 输出 3
gr1.switch() # 5. 切换到 func1 函数,从上一次执行位置向后执行
print(4) # 8. 输出 4
gr1 = greenlet(func1)
gr2 = greenlet(func2)
gr1.switch() # 1. 执行 func1 函数
yield
def func1():
yield 1
yield from func2()
yield 2
def func2():
yield 3
yield 4
for item in func1():
print(item)
asyncio
python 3.4 之后支持
import asyncio
@asyncio.coroutine
def func1():
print(1)
yield from asyncio.sleep(2)
print(2)
@asyncio.coroutine
def func2():
print(3)
yield from asyncio.sleep(2)
print(4)
tasks = [
asyncio.ensure_future(func1()),
asyncio.ensure_future(func2())
]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
遇到 IO 阻塞自动切换
async / await
python 3.5 之后支持
import asyncio
async def func1():
print(1)
await asyncio.sleep(2)
print(2)
async def func2():
print(3)
await asyncio.sleep(2)
print(4)
tasks = [
asyncio.ensure_future(func1()),
asyncio.ensure_future(func2())
]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
协程意义
一个线程中遇到 IO 等待时,线程不会傻等,利用空闲时间完成其他任务
异步编程
事件循环
事件循环的作用是管理所有的事件,在整个程序运行过程中不断循环执行,追踪事件发生的顺序将它们放到队列中,当主线程空闲的时候,调用相应的事件处理者来处理事件
快速上手
- 协程函数:async def 函数名
- 协程对象:执行 协程函数() 得到协程对象
async def func():
pass
# 执行协程函数得到协程对象,函数内部代码不会执行
result = func()
# 想要运行协程函数内部代码,必须要将协程对象交给事件循环处理
async def func():
print('test')
res = func()
loop = asyncio.get_event_loop()
loop.run_until_complete(res)
# py3.7+
asyncio.run(res)
await
await + 可等待的对象 (协程对象, Future, Task对象) IO等待
async def test():
print('test')
res = await asyncio.sleep(2)
Task对象
Tasks 用于并发调度协程,通过 asyncio.create_task(协程对象)
的方式创建 Task 对象,这样可以让协程加入事件循环中等到被调度执行
# Example 1
async def test():
print('test satart...')
await asyncio.sleep(2)
async def main():
print('start...')
task1 = asyncio.create_task(test())
task2 = asyncio.create_task(test())
await task1
await task2
asyncio.run(main())
# start...
# test satart...
# test satart...
# sleep 2
# Example 2
async def test():
print('test satart...')
await asyncio.sleep(1)
return '1'
async def main():
tasks = [
asyncio.create_task(test()),
asyncio.create_task(test()),
]
await asyncio.wait(tasks)
asyncio.run(main())