• Python中的协程


    目录

    1.实现协程的方法

    2.协程的意义

    3.异步编程

    3.1 事件循环

    3.2 快速上手

    3.3 await

    3.4 Task对象

    3.5 asyncio中的Future对象

    • 协程不是计算机提供,而是程序员人为创造
    • 协程(Coroutine),也可以被称为微线程,是一种用户态内的上下文切换技术,简而言之,其实就是通过一个线程实现代码块相互切换执行(用一个线程,在代码之间切换游走的执行)

    1.实现协程的方法

    • greenlet(早期模块)
    • yield关键字
    • asyncio(python3.4)
    • async & await关键字

    2.协程的意义

    在一个线程中如果遇到IO等待时间,线程不会一直等待,而是利用空闲的时候再去干点其他事情

    3.异步编程

    3.1 事件循环

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

    1. # 伪代码
    2. 任务列表 = [任务1, 任务2,任务3,。。。。]
    3. # 死循环
    4. while True:
    5. 可执行的任务列表,已完成的任务列表 = 去任务列表中检查所有的任务,将"可执行""已完成"的任务返回
    6. for 可执行任务 in 可执行的任务列表:
    7. 执行可执行的任务
    8. for 已完成的任务 in 已完成的任务列表:
    9. 在任务列表中移除 已完成的任务

    示例代码

    1. import asyncio
    2. # 去生成或者获取一个事件循环
    3. loop = asyncio.get_event_loop()
    4. # 将任务放到‘任务列表’
    5. loop.run_until_complete('任务')

    3.2 快速上手

    • 协程函数,定义函数时候 async def 函数名
    1. async def func():
    2. pass
    • 协程对象,执行协程函数()得到的协程对象
    • result = func()
    • 注意:执行协程函数创建协程对象,函数内部代码不会执行,如果执行协程函数代码,必须要将协程对象交给事件循环来处理

    3.3 await

    • await + 可等待的对象(协程对象、Future、 Task对象)【可以理解为IO等待】
    • await 就是等待对应的值得到结果之后,再继续向下走
    1. # 示例1
    2. import asyncio
    3. async def func():
    4. print("开始")
    5. response = await asyncio.sleep(2)
    6. print("结束", response)
    7. asyncio.run(func())
    8. """
    9. 运行结果:
    10. 开始
    11. (等两秒)
    12. 结束 None
    13. """
    1. # 示例2
    2. import asyncio
    3. async def others():
    4. print("start")
    5. await asyncio.sleep(2)
    6. print("end")
    7. return '返回值'
    8. async def func():
    9. print("执行协程函数内部代码")
    10. # 遇到 IO 操作挂起当前协程(任务), 等IO操作之后再继续往下执行,当前协程挂起时候,
    11. # 事件循环可以去执行其他协程(任务)
    12. response = await others()
    13. print("IO请求结束,结束为:", response)
    14. asyncio.run(func())
    15. """
    16. 执行协程函数内部代码
    17. start
    18. (等两秒)
    19. end
    20. IO请求结束,结束为: 返回值
    21. """
    1. # 示例3
    2. import asyncio
    3. async def others():
    4. print("start")
    5. await asyncio.sleep(2)
    6. print("end")
    7. return '返回值'
    8. async def func():
    9. print("执行协程函数内部代码")
    10. # 遇到 IO 操作挂起当前协程(任务), 等IO操作之后再继续往下执行,当前协程挂起时候,
    11. # 事件循环可以去执行其他协程(任务)
    12. response = await others()
    13. print("IO请求结束,结束为:", response)
    14. response2 = await others()
    15. print("IO请求结束,结束为:", response2)
    16. asyncio.run(func())
    17. """
    18. 运行结果:
    19. 执行协程函数内部代码
    20. start
    21. (等两秒)
    22. end
    23. IO请求结束,结束为: 返回值
    24. start
    25. (等两秒)
    26. end
    27. IO请求结束,结束为: 返回值
    28. """

    3.4 Task对象

    • 在事件循环中添加多个任务
    • 立即将某个任务添加到事件循环
    • 在事件循环里面并发的创建多个任务,让事件循环遇到IO自动切换处理
    • Task用于并发调度协程,通过asyncio.create_task(协程对象)的方式创建Task对象
    • 注意:asyncio.create_task() 函数 在 python3.7中被加入,在python3.7之前, 可以改用低层级的asyncio.ensure_future()函数
    1. import asyncio
    2. async def func1():
    3. print(1)
    4. await asyncio.sleep(2)
    5. print(2)
    6. return '返回值'
    7. async def func2():
    8. print(1)
    9. await asyncio.sleep(2)
    10. print(2)
    11. return '返回值'
    12. async def main():
    13. print("main开始")
    14. # 创建Task对象,将当前执行func函数任务添加到事件循环
    15. task1 = asyncio.create_task(func1())
    16. # 创建Task对象,将当前执行func函数任务添加到事件循环
    17. task2 = asyncio.create_task(func2())
    18. print('main结束')
    19. # 当执行某协程遇到IO操作时,会自动化切换执行其他任务
    20. # 此处的await是等待相应的协程全都执行完毕后并获取结果
    21. ret1 = await task1
    22. ret2 = await task2
    23. print(ret1, ret2)
    24. asyncio.run(main())
    25. """
    26. 运行结果:
    27. main开始
    28. main结束
    29. 1
    30. 1
    31. (等两秒)
    32. 2
    33. 2
    34. 返回值 返回值
    35. """
    1. # 示例2
    2. import asyncio
    3. async def func1():
    4. print(1)
    5. await asyncio.sleep(2)
    6. print(2)
    7. return '返回值'
    8. async def func2():
    9. print(1)
    10. await asyncio.sleep(2)
    11. print(2)
    12. return '返回值'
    13. async def main():
    14. print("main开始")
    15. task_list = [
    16. asyncio.create_task(func1()),
    17. asyncio.create_task(func2())
    18. ]
    19. print('main结束')
    20. # timeout : 最多等几秒
    21. # done -> 是一个集合
    22. done, pending = await asyncio.wait(task_list, timeout=None)
    23. print(done)
    24. asyncio.run(main())
    25. """
    26. main开始
    27. main结束
    28. 1
    29. 1
    30. (等两秒)
    31. 2
    32. 2
    33. { result='返回值'>, result='返回值'>}
    34. """
    1. # 实例3
    2. import asyncio
    3. async def func1():
    4. print(1)
    5. await asyncio.sleep(2)
    6. print(2)
    7. return '返回值'
    8. async def func2():
    9. print(1)
    10. await asyncio.sleep(2)
    11. print(2)
    12. return '返回值'
    13. task_list = [
    14. func1(),
    15. func2()
    16. ]
    17. done, pending = asyncio.run(asyncio.wait(task_list))
    18. print(done)
    19. """
    20. 1
    21. 1
    22. (等两秒)
    23. 2
    24. 2
    25. { result='返回值'>, result='返回值'>}
    26. """

    3.5 asyncio中的Future对象

    • Task继承Future, Task对象内部await结果的处理基于Future对象来的
    1. # 示例1
    2. import asyncio
    3. async def main():
    4. # 获取当前时间循环
    5. loop = asyncio.get_running_loop()
    6. # 创建一个任务(Future对象), 这个任务什么都不干
    7. fut = loop.create_future()
    8. # 等待任务最终结果(Future对象), 没有结果则会一直等下去。
    9. await fut
    10. asyncio.run(main())
    11. """
    12. 运行结果:
    13. 因为没有结果,则程序一直会等下去
    14. """
    1. import asyncio
    2. async def set_after(fut):
    3. await asyncio.sleep(2)
    4. fut.set_result("666")
    5. async def main():
    6. # 获取当前时间循环
    7. loop = asyncio.get_running_loop()
    8. # 创建一个任务(Future对象), 没绑定任何行为,则这个任务永远不知道什么时候结束
    9. fut = loop.create_future()
    10. # 创建一个任务(Task对象),绑定了 set_after 这个函数,函数内部在2s之后,会给fut赋值
    11. # 即手动设置,future 任务最终结果,那么fut就是可以结束了
    12. await loop.create_task(set_after(fut))
    13. # 等待任务最终结果(Future对象), 没有结果则会一直等下去。
    14. data = await fut
    15. print(data)
    16. asyncio.run(main())
    17. """
    18. 运行结果:
    19. 两秒之后打印
    20. 666
    21. """

  • 相关阅读:
    QRegExpValidator(正则验证器)
    Demo25重复元素II
    Vue2进阶篇-组件间通信的6钟方式
    css,环形
    洗鞋软件开发,洗鞋店小程序功能介绍;
    Go Go 简单的很,标准库之 fmt 包的一键入门
    文字与视频结合效果
    MATLAB算法实战应用案例精讲-【关联规则学习】Apriori算法(附matlab、python、Java、C++和R语言代码)
    leetcode 44. 通配符匹配(困难,dp)
    【单片机仿真项目】利用定时器0实现对LED灯的闪烁控制,LED灯的闪烁间隔为0.5秒
  • 原文地址:https://blog.csdn.net/wei18791957243/article/details/126553965