当前位置:系统粉 >   IT资讯 >   微软资讯 >  不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货

不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货

时间:2017-12-19 来源:互联网 浏览量:

例子1: follow.py 可以使用生成器完成 tail -f 的功能,也就是跟踪输出的功能。

不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货(1)

例子2: 生成器用作程序管道(类似unix pipe)

不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货(2)

pipeline.py

不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货(3)

理解pipeline.py

在pipeline中,follow函数和grep函数相当于程序链,这样就能链式处理程序。

Yield作为表达【我们开始说协程了~】:

grep.py

不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货(4)

yield最重要的问题在于yield的值是多少。

yield的值需要使用coroutine协程这个概念 相对于仅仅生成值,函数可以动态处理传送进去的值,而最后值通过yield返回。

协程的执行:

协程的执行和生成器的执行很相似。 当你初始化一个协程,不会返回任何东西。 协程只能响应run和send函数。 协程的执行依赖run和send函数。 如果你缺志同道合的朋友!缺学习Python的氛围!缺入门资料和视频!缺书籍的PDF!缺遇到问题没人解答?那就加这个群:103456743 你想要一起学习的朋友?资料免费提供的学习环境?好比图书馆!不收你一分钱,只为提供一个良好的交流平台!编程贵在多交流!

协程启动:

所有的协程都需要调用.next( )函数。 调用的next( )函数将要执行到第一个yield表达式的位置。 在yield表达式的位置上,很容易去执行就可以。 协程使用next()启动。

使用协程的修饰器:

由【协程启动】中我们知道,启动一个协程需要记得调用next( )来开始协程,而这个启动器容易忘记使用。 使用修饰器包一层,来让我们启动协程。 【以后所有的协程器都会先有@coroutine

不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货(5)

使用GeneratorExit这个异常类型

抛出一个异常:

在一个协程中,可以抛出一个异常

不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货(6)

不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货(7)

不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货(8)

第三部分,管道过滤器:

叫过滤器其实并不贴切,应该叫中间人Intermediate:其两端都是send()函数。

不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货(9)

(协程的中间层) 典型的中间层如下:

不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货(10)

协程和生成器的对比

不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货(11)

不同处:生成器使用了迭代器拉取数据,协程使用send()压入数据。

变得多分支:(上一个协程发送数据去多个下一段协程)

图示:

不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货(12)

使用协程,你可以发送数据 给 多个 协程过滤器/协程终了。但是请注意,协程源只是用来传递数据的,过多的在协程源中传递数据是令人困惑并且复杂的。

一个例子

不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货(13)

从文章中分别打印出含有’python‘ ’ply‘ ’swig‘ 关键字的句子。使用了一个协程队列向所有printer协程 送出 接收到的数据。 图示:

不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货(14)

或者这样Hook them up:

不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货(15)

第三部分:协程,事件分发

事件处理

协程可以用在写各种各样处理事件流的组件。

介绍一个例子【这个例子会贯穿这个第三部分始终】要求做一个实时的公交车GPS位置监控。编写程序的主要目的是处理一份文件。传统上,使用SAX进行处理。【SAX处理可以减少内存空间的使用,但SAX事件驱动的特性会让它笨重和低效】。

把SAX和协程组合在一起

我们可以使用协程分发SAX事件,比如:

不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货(16)

【最终的组合】

比如,把xml改成json最后从中筛选的出固定信息. buses.py

不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货(17)

协程的一个有趣的事情是,您可以将初始数据源推送到低级别的语言,而不需要重写所有处理阶段。比如,PPT 中69-73页介绍的,可以通过协程和低级别的语言进行联动,从而达成非常好的优化效果。如Expat模块或者cxmlparse模块。 ps: ElementTree具有快速的递增xml句法分析

第四部分:从数据处理到并发编程

复习一下上面学的特点:

协程有以下特点。

协程和生成器非常像。

我们可以用协程,去组合各种简单的小组件。

我们可以使用创建进程管道,数据流图的方法去处理数据。

你可以使用伴有复杂数据处理代码的协程。

一个相似的主题:

我们往协程内传送数据,向线程内传送数据,也向进程内传送数据。那么,协程自然很容易和线程和分布式系统联系起来。

基础的并发:

我们可以通过添加一个额外的层,从而封装协程进入线程或者子进程。这描绘了几个基本的概念。

不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货(18)

目标!协程+线程【没有蛀牙。

下面看一个线程的例子。 cothread.py

不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货(19)

例子解析:第一部分:先新建一个队列。然后定义一个永久循环的线程;这个线程可以将其中的元素拉出消息队列,然后发送到目标里面。第二部分:接受上面送来的元素,并通过队列,将他们传送进线程里面。其中用到了GeneratorExit ,使得线程可以正确的关闭。

Hook up:cothread.py

不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货(20)

不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货(21)

但是:添加线程让这个例子慢了50%

目标!协程+子进程

我们知道,进程之间是不共享系统资源的,所以要进行两个子进程之间的通信,我们需要通过一个文件桥接两个协程。

不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货(22)

不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货(23)

程序通过sendto()和recvfrom()传递文件。

和环境结合的协程:

使用协程,我们可以从一个任务的执行环境中剥离出他的实现。并且,协程就是那个实现。执行环境是你选择的线程,子进程,网络等。

需要注意的警告 :

创建大量的协同程序,线程和进程可能是创建 不可维护 应用程序的一个好方法,并且会减慢你程序的速度。需要学习哪些是良好的使用协程的习惯。

在协程里send()方法需要被适当的同步。

如果你对已经正在执行了的协程使用send()方法,那么你的程序会发生崩溃。如:多个线程发送数据进入同一个协程。

同样的不能创造循环的协程:

不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货(24)

堆栈发送正在构建一种调用堆栈(send()函数不返回,直到目标产生)。

如果调用一个正在发送进程的协程,将会抛出一个错误。

send() 函数不会挂起任何一个协程的执行。

第五部分:任务一样的协程

Task的概念

在并发编程中,通常将问题细分为“任务”。 “任务”有下面几个经典的特点: * 拥有独立的控制流。 * 拥有内在的状态。 * 可以被安排规划/挂起/恢复。 * 可与其他的任务通信。 协程也是任务的一种。

协程是任务的一种:

下面的部分 来告诉你协程有他自己的控制流,这里 if 的控制就是控制流。

不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货(25)

不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货(26)

需要解决的问题(还在复习微嵌知识)

CPU执行的是应用程序,而不是你的操作系统,那 没有被CPU执行的操作系统 是怎么控制 正在运行的应用程序 中断的呢。

中断(interrupts)和陷阱(Traps)

操作系统只能通过两个机制去获得对应用程序的控制:中断和陷阱。 * 中断:和硬件有关的balabala。 * 陷阱:一个软件发出的信号。 在两种状况下,CPU都会挂起正在做的,然后执行OS的代码(这个时候,OS的代码成功插入了应用程序的执行),此时,OS来切换了程序。

中断的底层实现(略…码字员微嵌只有70分��‍♀️)

中断的高级表现:

* 中断(Traps)使得OS的代码可以实现。* 在程序运行遇到中断(Traps)时,OS强制在CPU上停止你的程序。* 程序挂起,然后OS运行。

表现如下图:

不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货(27)

每次中断(Traps)程序都会执行另一个不同的任务。

任务调度(非常简单):

为了执行很多任务,添加一簇任务队列。

不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货(28)

启示(很重要):

BB了这么多微嵌的内容,得到的是什么结论呢。类比任务调度,协程中yield声明可以理解为中断(Traps)。当一个生成器函数碰到了yield声明,那函数将立即挂起。而执行被传给生成器函数运行的任何代码。如果你把yield声明看成了一个中断,那么你就可以组件一个多任务执行的操作系统了。

第七部分:让我们建一个操作系统。【起飞了,请握好扶手

目标:满足以下条件建成一个操作系统。

1. 用纯python语句。2. 不用线程。3. 不用子进程。4. 使用生成器和协程器。

我们用python去构建操作系统的一些动机:

* 尤其在存在线程锁(GIL)的条件下,在线程间切换会变得非常重要。我要高并发!* 不阻塞和异步I/O。我要高并发!* 在实战中可能会遇到:服务器要同时处理上千条客户端的连接。我要高并发!* 大量的工作 致力于实现 事件驱动 或者说 响应式模型。我要组件化!* 综上,python构建操作系统,有利于了解现在高并发,组件化的趋势。

第一步:定义任务

定义一个任务类:任务像一个协程的壳,协程函数传入target;任务类仅仅有一个run()函数。 pyos1.py

不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货(29)

在foo中,yield就像中断(Traps)一样,每次执行run(),任务就会执行到下一个yield(一个中断)。

第二步:构建调度者

下面是调度者类,两个属性分别是Task队列和task_id与Task类对应的map。schedule()向队列里面添加Task。new()用来初始化目标函数(协程函数),将目标函数包装在Task,进而装入Scheduler。最后mainloop会从队列里面拉出task然后执行到task的target函数的yield为止,执行完以后再把task放回队列。这样下一次会从下一个yield开始执行。 pyos2.py

不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货(30)

不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货(31)

第三步:确定任务的停止条件

如果,target函数里面不是死循环,那么上面的代码就会出错。所以我们对Scheduler做改进。添加一个从任务队列中删除的操作,和对于StopIteration的验证。 【对scheduler做改进的原因是任务的性质:可以被安排规划/挂起/恢复。】

不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货(32)

第四步:添加系统调用基类。

在OS中,中断是应用程序请求系统服务的方式。在我们的代码中,OS是调度者(scheduler),而中断是yield。为了请求调度者服务,任务需要带值使用yield声明。 pyos4.py

不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货(33)

代码解析: 1. 如果taskmap里面存在task,就从ready队列里面拿任务出来,如果没有就结束mainloop。 2. 【就是传说中的系统调运部分】ready队列里面的task被拿出来以后,执行task,返回一个result对象,并初始化这个result对象。如果队列里面的task要停止迭代了(终止yield这个过程)就从队列里删除这个任务。 3. 最后再通过schedule函数把执行后的task放回队列里面。 4. 系统调用基类,之后所有的系统调用都要从这个基类继承。

第4.5步:添加第一个系统调用

这个系统调用想返回任务的id。 Task的sendval属性就像一个系统调用的返回值。当task重新运行的是后,sendval将会传入这个系统调用。 pyos4.py

不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货(34)

理解这段代码的前提: (非常重要) 1. send()函数有返回值的,返回值是yield表达式右边的值。在本段代码中,result的返回值是yield GetTid()的GetTid的实例或者是yield后面的。 2. 执行send(sendval)以后,sendval被传入了yield表达式。并赋给了mytid,返回GetTid()给ruselt。

执行顺序: 先创建一个调度者(Scheduler),然后在调度者里面添加两个协程函数:foo(), bar(),最后触发mainloop进行协程的调度执行。

系统调用原理: 系统调用是基于系统调用类实现的,如GetTid类,其目的是传出自己的tid。传出自己的tid之后,再将task放回队列。

第五步:任务管理

上面我们搞定了一个GetTid系统调用。我们现在搞定更多的系统调用: * 创建一个新的任务。 * 杀掉一个已经存在的任务。 * 等待一个任务结束。 这些细小的相同的操作会与线程,进程配合。

1. *创建一个新的系统调用*:通过系统调用加入一个task。

不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货(35)

不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货(36)

不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货(37)

不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货(38)

网络服务器的搭建:

现在已经完成了: * 多任务。 * 开启新的进程。 * 进行新任务的管理。 这些特点都非常符合一个web服务器的各种特点。下面做一个Echo Server的尝试。

不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货(39)

但问题是这个网络服务器是I / O阻塞的。整个python的解释器需要挂起,一直到I/O操作结束。

非阻塞的I/O

先额外介绍一个叫Select的模块。select模块可以用来监视一组socket链接的活跃状态。用法如下:

不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货(40)

下面实现一个非阻塞I/O的网络服务器,所用的思想就是之前所实现的Task waiting 思想。

不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货(41)

源码解析:__init__里面的是两个字典。用来存储阻塞的IO的任务。waitforread()和waitforwrite()将需要等待写入和等待读取的task放在dict里面。这里的iopoll():使用select()去决定使用哪个文件描述器,并且能够不阻塞任意一个和I/O才做有关系的任务。poll这个东西也可以放在mainloop里面,但是这样会带来线性的开销增长。 详情请见: Python Select 解析 - 金角大王 - 博客园

添加新的系统调用:

不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货(42)

更多请见开头那个连接里面的代码:pyos8.py

这样我们就完成了一个多任务处理的OS。这个OS可以并发执行,可以创建、销毁、等待任务。任务可以进行I/O操作。并且最后我们实现了并发服务器。

第八部分:协程栈的一些问题的研究。

我们可能在使用yield的时候会遇到一些问题:

不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货(43)

让我们来看看这个叫蹦床的奇淫巧技。

代码:trampoline.py

不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货(44)

整个控制流如下:

不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货(45)

我们看到,上图中左侧为统一的scheduler,如果我们想调用一个子线程,我们都用通过上面的scheduler进行调度。

不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货(46)

千万不要一个函数里面包含两个或多个以上的功能,比如函数是generator就是generator,是一个coroutine就是一个coroutin。

谢谢阅读!

不会协程你想拿高薪?那是不存在的!微软工程师带来最全协程干货(47)

如有侵权请联系小编删除哦!

我要分享:

最新热门游戏

版权信息

Copyright @ 2011 系统粉 版权声明 最新发布内容 网站导航