1.初学Python,源码有哪些Pythonic的源码源码推荐阅读
2.pyhton协程-gevent
3.Gevent源码剖析(二):Gevent 运行原理
初学Python,有哪些Pythonic的源码源码推荐阅读
1. 初学Python时,阅读Pythonic的源码源码是提高编程技能的有效方法。推荐从Python标准库中关于网络编程的源码代码开始学习。
2. 首先,源码wp论坛社区源码深入研究`SocketServer`模块,源码它为创建服务器提供了基础。源码同时,源码学习与之相关的源码`socket`模块,掌握TCP和UDP编程的源码基础知识。
3. 接下来,源码关注`SocketServer`模块中的源码`ForkingMixIn`和`ThreadingMixIn`类,它们分别展示了forking和threading并发机制的源码混合使用,这是源码理解多线程和多进程编程的重要途径。
4. 了解`thread`和`threading`模块,这对于管理并发执行的线程至关重要。
5. 随后,研究`select`模块,它允许你处理I/O多路复用,这是理解操作系统如何高效处理并发I/O操作的关键。
6. 通过学习`select`模块,武易源码你将自然过渡到对`selectors`的理解,这是Python 3.7引入的更现代的I/O多路复用API。
7. 对于想要深入了解并发编程的初学者,可以学习`asyncore`和`asynchat`模块,它们是异步网络编程的基础。
8. 在网络编程的基础上,如果你的兴趣在于游戏开发或实时应用,可以探索`greenlet`和`gevent`,这些库提供了协程,有助于编写高效的并发代码。
9. 如果你对Web开发感兴趣,从`BaseHTTPServer`、`SimpleHTTPServer`和`CGIHTTPServer`开始你的学习之旅。这些模块可以帮助你理解基本的Web服务器和CGI(Common Gateway Interface)。
. 学习`cgi`和`cgitb`模块,这对于调试和运行CGI脚本非常有用。
. 掌握`cookielib`模块,它处理HTTP cookies,这对于处理用户会话和状态管理至关重要。
. 阅读`wsgiref`模块的源码,它是cps分销源码一个WSGI(Web Server Gateway Interface)参考实现,有助于你理解现代Web框架的工作原理。
. 学习如何编写自己的简单Web框架后,你可以更容易地理解并选择`Flask`、`Web.py`、`Django`或`Pyramid`等流行的Web框架。
. 在进行Web开发时,不可避免地需要与API进行交互。因此,熟悉`httplib`、`urllib`和`urlparse`模块是很重要的,它们帮助你处理HTTP请求和响应。
通过以上步骤,初学者可以逐步建立起对Python网络和Web编程的深刻理解,为进一步的编程之旅打下坚实的基础。
pyhton协程-gevent
线程模型
线程的实现模型主要由3种:内核级线程模型、用户级线程模型、混合型线程模型。它们最大的区别在于线程与内核调度实体KSE(Kernel Scheduling Entity)之间的对应关系,可以被操作系统内核调度的对象实体,也称为内核级线程,操作系统内核最小调度单元。天下游源码
英文叫Coroutine,通俗点叫用户态线程,但区别于线程的抢占式调度,使用的是协作调度,从一个状态开始一条执行流在多个协程间切换,好像多个协程写作完成一项任务。
关于生成器,我们知道是使用yield的迭代器具体代码:
这个执行过程就是当我们生成一个a的generator时,代码已经执行到yield,程序被挂住,然后调用一次next(a)此时继续执行返回yield后面的i。我们能在通过next(a)来控制它的执行流程,从而实现不同子程序的之间的交替执行。
在python的PEP-里有对yield做了增强,能够传入值,能够在try-finally里使用等等,是生成器更能被用作协程。
协程,协作式调度的,而不是抢占式调度,greenlet是muduo 源码分析python的一个C扩展,能够提供自行调度的协程,他比yield协程的好处就是能够在一个协程传递参数给另一个协程(在switch函数中传值,虽然yield也能给协程传值,但是我们是必须在主函数的调度算法里。
上面共启动了两个greenlet协程,首先在主线程中通过gr1.switch()切换到test1函数,执行到gr2.switch()我们切换到了函数test2,随后又一次切换到了test1,最后当test1函数退出将直接返回到主线程所以我们能看到的输出就是:
多个greenlet可以共存在一个线程中,但是任意时刻一个线程中只有一个greenlet在运行。
为了让另一个greenlet运行,当前运行的greenlet必须放弃控制权,这叫做切换。切换时必须明确选择要让哪个greenlet来接替执行,当前的greenlet里调用目的地greenlet的switch方法来进行这样的切换。当切换发生时,当前greenlet的调用栈会被保存下来,目的地greenlet的调用栈被放到正确的位置,然后执行流在目的地greenlet上次切换的地方继续执行。
一个第三方协程库,基于greenlet实现自己的协程调度机制,实现的是协作式调度,区别于CPU的抢占式调度。
事件循环
hub是gevent中最重要的一部分
hub本身也是一个greenlet,在hub里我们运行着gevent的核心之一loop也就是事件循环,loop里封装着对应着底层libev的各个接口,当loop运行的时候,它将会用于处理所有的greenlet都可以通过get_hub获取当前的hub对象,若果不存在就重新创建一个。任何一个greenlet切换后都将进入到hub这个greenlet里,如果此时没有开启事件轮训就主动开启,之后便等待下一个greenlet的回调事件。
其中get_hub获取hub对象
在python的标准库里socket默认是阻塞模式,这种模式下它的许多函数都是阻塞的,其中就包括recv(),接收对端发送的数据。
转了一堆弯找到最终调用的是hub.wait(),首先声明一个Waiter对象,将waiter.switch函数传入到绑定了当前socket读事件的io watcher,当watcher监听到有数据到来时,就执行回调函数waiter.switch
到现在我们还不知道,在当前greenlet切出进hub中,到最后socket收到对端发送来消息,watcher回调成功切入到当前greenlet这段时间里,究竟gevent在干嘛。这个问题先放着,我们去探究另一个问题。
hub是怎么管理的greenlet的
我们可以从一个gevent的使用例子来看
看函数名,spawn就是产生一个什么东西,那现在用的是gevent那大概率是生产一个协程
看代码,我们发现就是初始化了一个Greenlet(继承自greenlet类,后者为c库greenlet接口的封装)实例,然后调用start最后返回它。那我们知道,我们首先去看这个类的初始化方法,发现有这么一行
这里的parent,参数就是我们的hub,没错,在同一线程内生成一个协程,都会指定它的parent为同一个hub,这样当协程执行完退出时就不会退出到主线程,而是会跳到我们的hub协程。
我们再看下start方法
到此也只是注册两个协程,并没有实际运行,我们再看下join(),简化代码我们看到这段。
到此也只是注册两个协程,并没有实际运行,我们再看下join(),简化代码我们看到这段。
其实这就是切换到hub这个greenlet,正如switch这个方法定义的:
我们去看下hub的self.run干了些什么,简化一下
大概逻辑就是执行我们事件循环loop,从Hub出发去寻找Loop最终代码落入到gevent.libev.corecffi.loop(如果是linux环境)再往里就调用c的lib库了,具体事件循环对象暴露哪些接口我们可以看gevent._interfaces.ILoop, loop.run()做的执行底层livev的事件监听,当有事件被触发,就会执行当时注册的回调函数waiter.switch这样就切换回指定的协程。
由python创始人亲自操刀的异步编程标准库,核心组件除了事件循环、Coroutine 还有任务(Task)、未来对象(Future)。
Gevent源码剖析(二):Gevent 运行原理
Gevent的运行原理在python2.7.5版本下,涉及多个关键概念。简单来说,它通过Greenlet类和Hub事件循环实现并发执行。以下是核心步骤:
首先,通过导入gevent模块,引入其初始化设置,greenlet的运行函数通过gevent.spawn()方法注册到Hub,这个过程包括获取Hub实例、初始化greenlet并保存函数和参数。get_hub()利用线程局部存储保证Hub的多线程一致性。
接着,greenlet通过g.start()注册到事件循环,回调事件由switch()控制,而不是直接运行函数,实现了协程的切换。Gevent提供了join()和joinall()两个入口,其中joinall()控制了整个流程。
在详细流程中,iwait()函数扮演重要角色,通过创建Waiter对象,将协程的switch()链接到目标,通过waiter.get()控制协程执行和返回。Hub事件循环与运行协程通过waiter.get()和waiter.switch()协同工作,实现了并发执行。
目标协程的执行涉及事件循环的启动,通过Cython调用libev库执行。目标函数在run()中执行,并通过_report_result()和_report_error()处理结果或异常。"绿化"函数是实现并发的关键,它们允许在等待I/O操作时释放控制权,从而实现多任务并发。
总的来说,Gevent的运行涉及复杂的协程调度和事件驱动,虽然本文仅触及表面,但其背后的并发机制和技术细节更为丰富,包括异常处理和大量"绿化"函数的使用,这将在后续深入探讨。