协程

  • 协程不是真是存在的,程序员人为创造出来的(上下文切换的技术)
  • 协程:可以成为微线程,是一种用户态的上下文切换技术,简而言之,其实就是通过一个线程实现代码块相互切换执行。
def func1():
  print(1)
  print(2)
  print(3)
def fun2():
  print(3)
  print(4)
func1()
func2()

实现协程

  • greenlet
  • yield关键字
  • asyncio 装饰器
  • async、 await关键字(3.5)【⭐】

1.1 Greenlet 实现协程

  • pip install greenlet

1.2 yield 关键字

1.3asyncio

python 3.4以及之后

    import asyncio
    @asyncio.coroutine
    def func1():
        print(1)
        yield from asyncio.sleep(2)  # 遇到IO耗时操作,自动化切换到tasks中的其他任务
        print(2)
    @asyncio.coroutine
    def func2():
        print(3)
        yield from asyncio.sleep(2) # 遇到IO耗时操作,自动化切换到tasks中的其他任务
        print(4)
    tasks = [
        asyncio.ensure_future( func1() ),
        asyncio.ensure_future( func2() )
    ]
    loop = asyncio.get_event_loop()
    loop.run_until_complete(asyncio.wait(tasks))

注意:遇到io阻塞会自动i切换

3.5 async & await关键字

    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))

2.协程的意义

在一个线程中如果遇到IO等待时间,线程不会傻等,空闲的时间再去干点其他事

案例:下载三张图片

  • 同步:一个接一个的执行
  • 异步:一个跳一个

3.异步编程

## 3.1事件循环

理解成为一个死循环,去检测并执行代码

# 伪代码
任务列表 =[任务1,任务2,任务3,..]
while True:
 for 就绪任务 in 可执行的任务列表:
    执行已就绪的任务
 for 已完成的任务 in 已完成的任务列表:
   在任务列表中移除 已完成的任务
improt asyncio
# 去生成或获取一个事件循环
loop= asyncio.get_event_loop()
# 将任务放到‘任务列表’
loop.run_until_complete(任务)

3.2 快速上手

协程函数,定义函数时 async def 函数名。

协程对象,执行 协程函数()得到协程对象。

anync def func() :  #协程函数
   pass
result = func() #协程对象

注意:执行协程函数创建协程对象,函数内部代码不运行

如果想要运行协程函数内部代码, 必须要将写成对象交给事件循环来处理。

anync def func() :  #协程函数
   printf("少女起到中")
result = func() #协程对象


# 去生成或获取一个事件循环
loop= asyncio.get_event_loop()
# 将任务放到‘任务列表’
loop.run_until_complete(result)

# asyncio.run(result) #python3.7
import asyncio
async def func():
    print("Eva...")
result = func()
asyncio.run(result)

3.3 await

await + 可等待的对象 (协程对象、future、task对象->IO等待)]

import asyncio
async def func():
    print("来玩啊")
    await asyncio.sleep(2) #等待执行其他
    print("结束")
asyncio.run(func())
    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() )

3.4 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() 函数。

示例一

    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())