python协程
1.协程前奏概念
并发:在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任一个时刻点上只有一个程序在处理机上运行。
并发:当有多个线程在操作时,如果系统只有一个CPU,则它根本不可能真正同时进行一个以上的线程,它只能把CPU运行时间划分成若干个时间段,再将时间 段分配给各个线程执行,在一个时间段的线程代码运行时,其它线程处于挂起状。.这种方式我们称之为并发(Concurrent)。
并行:当系统有一个以上CPU时,则线程的操作有可能非并发。当一个CPU执行一个线程时,另一个CPU可以执行另一个线程,两个线程互不抢占CPU资源,可以同时进行,这种方式我们称之为并行(Parallel)。
同步:调用IO时,等待IO返回才能操作
异步:调用IO时,不必等待IO返回,直接进行下一步
阻塞: 阻塞调用是指调用结果返回之前,当前线程会被挂起。函数只有在得到结果之后才会返回
非阻塞:非阻塞和阻塞的概念相对应,指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回
2.协程概念
#传统函数调用 过程 A->B->C
协程:#我们需要一个可以暂停的函数,并且可以在适当的时候恢复该函数的继续执行
#出现了协程 -> 有多个入口的函数,可以暂停的函数,可以暂停的函数(可以向暂停的地方传入值)
协程 自定义异常 yield yeild和yield fromyield from
我们有一个嵌套型的序列,想将它扁平化处理为一列单独的值。
代码 运行结果collections.Iterable是一个抽象基类,我们用isinstance(x, Iterable)检查某个元素是否是可迭代的.如果是的话,那么就用yield from将这个可迭代对象作为一种子例程进行递归。最终返回结果就是一个没有嵌套的单值序列了。
代码中额外的参数ignore types和检测语句isinstance(x, ignore types)用来将字符
串和字节排除在可迭代对象外,防止将它们再展开成单个的字符。
如果这里不用yield from的话,那么就需要另外一个for来嵌套,并不是一种优雅的操作
yield from 的主要功能是打开双向通道,把最外层的调用方与最内层的子生成器连接起来,这样二者可以直接发送和产出值,还可以直接传入异常,而不用在位于中间的协程中添加大量处理异常的样板代码。有了这个结构,协程可以通过以前不可能的方式委托职责
生成器消费者和生产者
生产者和消费者yield from的使用
yield from
yield from 实例
统计方法yield from 可以获取子生成器的retunrn的值
看完代码,我们总结一下关键点:
1. 子生成器生产的值,都是直接传给调用方的;调用方通过.send()发送的值都是直接传递给子生成器的;如果发送的是 None,会调用子生成器的__next__()方法,如果不是 None,会调用子生成器的.send()方法;
2. 子生成器退出的时候,最后的return EXPR,会触发一个StopIteration(EXPR)异常;
3. yield from表达式的值,是子生成器终止时,传递给StopIteration异常的第一个参数;
4. 如果调用的时候出现StopIteration异常,委托生成器会恢复运行,同时其他的异常会向上 "冒泡";
5. 传入委托生成器的异常里,除了GeneratorExit之外,其他的所有异常全部传递给子生成器的.throw()方法;如果调用.throw()的时候出现了StopIteration异常,那么就恢复委托生成器的运行,其他的异常全部向上 "冒泡";
6. 如果在委托生成器上调用.close()或传入GeneratorExit异常,会调用子生成器的.close()方法,没有的话就不调用。如果在调用.close()的时候抛出了异常,那么就向上 "冒泡",否则的话委托生成器会抛出GeneratorExit异常。
3.原生协程 async/wait
# 生成器是可以暂停的函数
# 第一返回值给调用方, 第二调用方通过send方式返回值给gen
# 用同步的方式编写异步的代码, 在适当的时候暂停函数并在适当的时候启动函数