协程,又称微线程,纤程。英文名Coroutine。

线程是系统级别的它们由操作系统调度,而协程则是程序级别的由程序根据需要自己调度。在一个线程中会有很多函数,我们把这些函数称为子程序,在子程序执行过程中可以中断去执行别的子程序,而别的子程序也可以中断回来继续执行之前的子程序,这个过程就称为协程。也就是说在同一线程内一段代码在执行过程中会中断然后跳转执行别的代码,接着在之前中断的地方继续开始执行,类似与yield操作。

协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈。因此:协程能保留上一次调用时的状态(即所有局部状态的一个特定组合),每次过程重入时,就相当于进入上一次调用的状态,换种说法:进入上一次离开时所处逻辑流的位置。

协程,英文名是 Coroutine, 又称为微线程,是一种用户态的轻量级线程。协程不像线程和进程那样,需要进行系统内核上的上下文切换,协程的上下文切换是由程序员决定的。在 Python 中协程就是一个可以暂停执行的函数,听起来和生成器的概念一样。

协程的优点:

  (1)无需线程上下文切换的开销,协程避免了无意义的调度,由此可以提高性能(但也因此,程序员必须自己承担调度的责任,同时,协程也失去了标准线程使用多CPU的能力)

  (2)无需原子操作锁定及同步的开销

  (3)方便切换控制流,简化编程模型

  (4)高并发+高扩展性+低成本:一个CPU支持上万的协程都不是问题。所以很适合用于高并发处理。

协程的缺点:

  (1)无法利用多核资源:协程的本质是个单线程,它不能同时将 单个CPU 的多个核用上,协程需要和进程配合才能运行在多CPU上.当然我们日常所编写的绝大部分应用都没有这个必要,除非是cpu密集型应用。

  (2)进行阻塞(Blocking)操作(如IO时)会阻塞掉整个程序

yield

def test():
for i in 'abc':
yield i
for i in [1, 2, 3]:
yield i if __name__ == '__main__':
gen = test()
print(gen.send(None))
print(gen.send(None))
print(gen.send(None))
print(gen.send(None))
print(gen.send(None))
print(gen.send(None))
print(gen.send(None))
def test():
for i in 'abc':
yield i
for i in [1, 2, 3]:
yield i if __name__ == '__main__':
gen = test()
for i in gen:
print(i)

使用for循环生成器,因为for循环可以捕捉StopIteration异常。

yield from

上面的代码也可以用yield from实现

def test():
yield from 'abc'
yield from [1, 2, 3] if __name__ == '__main__':
gen = test()
for i in test():
print(i)

yield from 后面需要加的是可迭代对象,它可以是普通的可迭代对象,也可以是迭代器,甚至是生成器。

使用yield from实现实时计算器

def average_gen():
"""
子生成器
"""
average = 0
total = 0
count = 0
while True:
num = yield average
if num is None:
break
count += 1
total += num
average = total / count
return average, count, total def proxy_gen():
"""
委派生成器
"""
while True:
average, count, total = yield from average_gen()
print(f'平均值{average}, 计算{count}次, 总和{total}') def client():
"""
调用端
"""
calc_average = proxy_gen()
calc_average.send(None)
# next(calc_average)
# 预激活协程
print(calc_average.send(10))
print(calc_average.send(20))
print(calc_average.send(30))
calc_average.send(None)
# 关闭协程 if __name__ == '__main__':
client()

在委派生成器中的while True可以替换成for循环,循环的大小决定调用端可以calc_average.send(None)的次数(第一次预激活也计入)。

while Truefor循环用来捕捉StopIteration异常,可以查看第一段代码。

示例

def average_gen():
"""
子生成器
"""
average = 0
total = 0
count = 0
while True:
num = yield average
if num is None:
break
count += 1
total += num
average = total / count
return average, count, total def proxy_gen():
"""
委派生成器
"""
for i in range(2):
average, count, total = yield from average_gen()
print(f'平均值{average}, 计算{count}次, 总和{total}') def client():
"""
调用端
"""
calc_average = proxy_gen()
calc_average.send(None)
# next(calc_average)
# 预激活协程
print(calc_average.send(10))
print(calc_average.send(20))
print(calc_average.send(30))
calc_average.send(None)
# 关闭协程
print(calc_average.send(10))
print(calc_average.send(20))
print(calc_average.send(30))
calc_average.send(None) if __name__ == '__main__':
client()

示例最后会抛出StopIteration异常。

因为在第二次calc_average.send(None)时,for循环捕捉了一次异常,进入了最后一次循环,在calc_average.send(None)时,for不能再次循环,不能处理StopIteration异常,故抛出。

Python协程一点理解的更多相关文章

  1. Python协程深入理解

    从语法上来看,协程和生成器类似,都是定义体中包含yield关键字的函数.yield在协程中的用法: 在协程中yield通常出现在表达式的右边,例如:datum = yield,可以产出值,也可以不产出 ...

  2. Python协程深入理解(转)

    原文:https://www.cnblogs.com/zhaof/p/7631851.html 从语法上来看,协程和生成器类似,都是定义体中包含yield关键字的函数.yield在协程中的用法: 在协 ...

  3. Python 协程总结

    Python 协程总结 理解 协程,又称为微线程,看上去像是子程序,但是它和子程序又不太一样,它在执行的过程中,可以在中断当前的子程序后去执行别的子程序,再返回来执行之前的子程序,但是它的相关信息还是 ...

  4. 带你简单了解python协程和异步

    带你简单了解python的协程和异步 前言 对于学习异步的出发点,是写爬虫.从简单爬虫到学会了使用多线程爬虫之后,在翻看别人的博客文章时偶尔会看到异步这一说法.而对于异步的了解实在困扰了我好久好久,看 ...

  5. 异步等待的 Python 协程

    现在 Python 已经支持用协程进行异步处理.但最近有建议称添加协程以全面完善 Python 的语言结构,而不是像现在这样把他们作为生成器的一个类型.此外,两个新的关键字---异步(async)和等 ...

  6. Day10 - Python协程、异步IO、redis缓存、rabbitMQ队列

    Python之路,Day9 - 异步IO\数据库\队列\缓存   本节内容 Gevent协程 Select\Poll\Epoll异步IO与事件驱动 Python连接Mysql数据库操作 RabbitM ...

  7. day-5 python协程与I/O编程深入浅出

    基于python编程语言环境,重新学习了一遍操作系统IO编程基本知识,同时也学习了什么是协程,通过实际编程,了解进程+协程的优势. 一.python协程编程实现 1.  什么是协程(以下内容来自维基百 ...

  8. Python协程、异步IO

    本节内容 Gevent协程 Select\Poll\Epoll异步IO与事件驱动 Python连接Mysql数据库操作 RabbitMQ队列 Redis\Memcached缓存 Paramiko SS ...

  9. python协程的简单了解

    协程: 协程,又称微线程,纤程.英文名Coroutine. 可以在不同的函数间切换,而且切换的次数和时间都是由用户自己确定的. 协程的几种实现方式: (1)使用生成器yield实现. 如果不了解生成器 ...

随机推荐

  1. Java设置Client Socket链接Server超时时间

    Java设置Client Socket链接Server超时时间 学习了:http://blog.csdn.net/tterminator/article/details/52494141 http:/ ...

  2. hadoop-02-关闭防火墙

    hadoop-02-关闭防火墙 su root service iptables status #查看状态 即时关闭: service iptables stop #关闭 重启之后关闭: chkcon ...

  3. 黑马day14 踢人小案例

    本案例介绍: 使用监听器来实现踢人小案例,仅仅有管理员才有踢人的功能. 1.搭建开发环境,导入本案例须要的jar包.以及一个准备好的数据库工具类:提供数据源的方法...当中我已经在数据库中加入了三个用 ...

  4. Activity生命周期的运行流程

    Activity的生命周期运行流程:  ·当Activity第1次被启动:     ·onCreate()->onStart()->onResume()  ·当Activity被遮挡后再次 ...

  5. Sqlite3的安装Windows

  6. 智课雅思词汇---十、pend是什么意思

    智课雅思词汇---十.pend是什么意思 一.总结 一句话总结:[词根含义]:悬挂,垂;称量;支付 词根:-pend-, -pens- [词根含义]:悬挂,垂;称量;支付 [词根来源]:来源于拉丁语动 ...

  7. 转载-让PIP源使用国内镜像,提升下载速度和安装成功率

    让PIP源使用国内镜像,提升下载速度和安装成功率. 对于Python开发用户来讲,PIP安装软件包是家常便饭.但国外的源下载速度实在太慢,浪费时间.而且经常出现下载后安装出错问题.所以把PIP安装源替 ...

  8. [NOI2002] Savage 解题报告(扩展欧几里得)

    题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1407 Description 克里特岛以野人群居而著称.岛上有排列成环行的M个山洞.这些 ...

  9. The evolution of cluster scheduler architectures--转

    原文地址:http://www.firmament.io/blog/scheduler-architectures.html cluster schedulers are an important c ...

  10. PGA和UGA内存的使用情况

    引用thomas kyte的PGA和UGA的统计内存的使用情况,用排序区不同的大小来查看pga.UGA.物理读取不同内存使用 会话1:创建测试表和测试不同排序大小 create table t as ...