python协程 过程 例子:

协程又称为微线程,协程是一种用户态的轻量级线程

协程拥有自己的寄存器和栈。协程调度切换的时候,将寄存器上下文和栈都保存到其他地方,在切换回来的时候,恢复到先前保存的寄存器上下文和栈,因此:协程能保留上一次调用状态,每次过程重入时,就相当于进入上一次调用的状态。

优点

  1. 无需线程上下文切换的开销(还是单线程)
  2. 无需原子操作(一个线程改一个变量,改一个变量的过程就可以称为原子操作)的锁定和同步的开销
  3. 方便切换控制流,简化编程模型
  4. 高并发+高扩展+低成本:一个cpu支持上万的协程都没有问题,适合用于高并发处理

缺点

  1. 无法利用多核的资源,协程本身是个单线程,它不能同时将单个cpu的多核用上,协程需要和进程配合才能运用到多cpu上(协程是跑在线程上的)
  2. 进行阻塞操作时会阻塞掉整个程序:如io

过程

yield工作原理

从语法上来看,协程和生成器类似,都是定义体中包含yield关键字的函数。

yield在协程中的用法:

yield通常出现在表达式的右边,例如:x = yield,如果yield关键字后面没有表达式,那么生成器产出None
在协程中yield也可能从调用方接受数据,调用方是通过x.send()的方式把数据提供给协程使用,而不是next()函数,通常调用方会把值推送给协程。
协程可以把控制器让给中心调度程序,从而激活其他的协程。
所以总体上在协程中把yield看做是控制流程的方式。


例子:

def averager():
    total = 0.0
    count = 0
    average = None
    while True:
        term = yield average
        total += term
        count += 1
        average = total/count
        print(f'nAverage count: {average} / {count}')

avg = averager()
next(avg)
print(avg.send(10))
print(avg.send(30))
print(avg.send(40))

Result:

Average count: 10.0 / 1
10.0

Average count: 20.0 / 2
20.0

Average count: 26.666666666666668 / 3
26.666666666666668

分析

yield的右边没有表达式,所以这里默认产出的值是None
刚开始先调用了next()是因为这个时候生成器还没有启动,没有停在yield那里,此时无法通过send()发送数据。所以当我们通过next()激活协程后,程序就会运行到average = yield

注意,average = yield先计算等号右边的内容,再进行赋值,所以当激活生成器后,程序会停在yield这里,但并没有给average赋值。

当我们调用send()方法后yield会收到这个值并赋值给average,而当程序运行到协程定义体的末尾时和用生成器的时候一样会抛出StopIteration异常




python

本博客所有文章均采用 CC BY-SA 4.0协议 。转载请注明出处!



常用国内源
上一篇

Python同一运算符
下一篇