欢迎光临
我们一直在努力

深入理解python中的协程

文章目录

    • 协程简介
    • 语法和架构

协程是一种轻量级的异步编程方案,通过挂起和恢复机制实现高效并发。相比多线程方案,协程不依赖操作系统调度,资源消耗更低。Python通过async/await关键字实现协程:async标记协程函数,await实现挂起恢复。典型使用流程包括create_task创建任务、gather打包任务、run运行任务。示例展示了协程如何实现非阻塞并发执行,在I/O密集型任务中显著提升效率。协程机制完全由语言层面实现,对操作系统透明。

协程简介

想象一个简单的通信场景,A向B发送一条指令,并等待回传。按照传统的顺序编程逻辑,当A的指令发出后,它只能站在原地干等着,这也意味着,在B的信息传回来之前,A也不能和其他人通信,不仅低效,而且会引发错误。

一种简单的解决方案是多线程,A分裂出许多个线程,

a

1

a_1

a1​线程发出消息后,固然站在原地等待,但

a

2

⋯

a

n

a_2\\cdots a_n

a2​⋯an​这段时间并不闲着,从而继续利用资源。但这种解决方案也有天花板,因为内存的容量是有限的,A不可能分裂出无限多个线程,所以随着B的数量增多,这种并发方案也要吃不消。

最合理的方案是,当A发出信息后,不再傻等着,而是该干啥干啥,直到B的消息传回来之后,再临时回到和B通信的任务中,这就是异步编程的逻辑。下面是Python中采用异步编程的最简示例

import asyncio

async def job(n):
print('start', n)
await asyncio.sleep(n)
print('end ', n)

async def main():
t1 = asyncio.create_task(job(1))
t2 = asyncio.create_task(job(2))
await asyncio.gather(t1, t2)

asyncio.run(main())

'''打印结果如下
start 1
start 2
end 1
end 2
'''

这个程序很简单,job的功能是,先打印一个start,然后沉睡n秒,再打印end。正常情况下,如果采用顺序编程,那么连续调用两次job,只有在第一次job执行完毕之后,才能执行第二次。而在asyncio的调度下,当执行完

t

1

t_1

t1​的start任务后,就不管

t

1

t_1

t1​,而是去执行

t

2

t_2

t2​的start了,由此才能实现异步并发这种现象。

语法和架构

如果打开任务管理器,每一个应用都是一个进程,它们的工作模式叫做并行——前提是核心管够;如果应用可以被展开,那么里面的每一个子项目,都是一个线程,其工作模式叫做并发,即在系统的协调下,它们之间快速转换对CPU的占用,看上去就像是一起发生一样。

而我们刚刚创建的程序在运行的时候,任务管理器没有任何变化,即操作系统并不能识别出异步编程所带来的影响,这种不依托操作系统的异步程序,可称之为协程。由于协程的工作逻辑仅依托于语言本身,故而需要有一个明显的标记,告诉解释器,从哪里开始需要等待。正因如此,async和await才会夸张到成为Python的关键字,其中

  • 【async】负责创建协程,当解释器看到后,就会识别这是个协程函数,然后生成一张数据表,为挂起/恢复做准备
  • 【await】负责挂起/恢复协程,当解释器看到后,会将其冻结,同时拿到一个闹钟,闹钟一响,再解冻。

根据上面的示例,想要运行协程,主要分三步

  • create_task创建协程
  • gather将多个协程打包
  • run来运行打包后的协程
  • 这三步走流程,底层其实是由一个名为事件循环的调度器在默默运转。你可以把它想象成一个不知疲倦的“交通指挥员”。当我们调用 asyncio.run(main()) 时,实际上就是把这个指挥员请上了岗,并正式启动调度。

    赞(0)
    未经允许不得转载:171主机测评 » 深入理解python中的协程
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址