Gevent: greenlets 和 monkey-patching我们的代码里要假定没用sleep? 我们可以用gevent的猴子补丁来确保不需要更改代码:
标准库中的大部分阻塞调用都会被打补丁,这样可以用hub调度而不必堵塞。同样的,线程系统会用微线程代替线程。 monkey-patching很糟糕吗?在这种情况下,最好把gevent当做python的一部分,它使用了green thread,然后包含标准库代码的不同实现. 部分原因是,它必须在包含程序入口的模块的最开头.它是在代码运行前,我们使用gevent版本stdlib的一个声明. monkey patching是优雅的,它允许纯Python应用程序和库在不做修改的情况下变成异步的.它是gevent的一个可选组件,不需要它也可以编写异步程序.
gevents线程原语的例子因为gevent是基于轻量级的"线程",所以gevent库包含大量的并发工具来生成greenlet,实现临界区(锁和互斥变量)以及在greenlet之间传递消息. 因为它是一个网路库,所以也包含了一些高级别的网路服务模块,如TCP服务器和WSGI服务器. 生成和杀死greenlets
这里也有一些高级别的原语,像gevent.pool,它基于greenlet,与multiprocessing.pool对等. 同步原语
消息传递
超时这里有一个有用的包装器,可以用来杀死一个段时间内都没有成功运行的greenlet.它可以用来在其他一系列操作中引入超时.
更高级别的服务器工具
Gevent I/O模式使用gevent (避免使用select())时,推荐为各个方面的交互生成一个greenlet--包括读和写.每个greenlet的代码只是一个简单的循环,在需要时可以阻塞.查看早前的chat server 的代码作为示例. 为什么我们想要一个同步的编程模型?首先,它让代码更易懂易读.它和单线程是一样的编程方式.使用yield后代码不会分散. 更重要的是,上面描述的这些方法,只有gevent不需要改变代码的调用约定.这个重要性不应该被低估,它意味着业务逻辑代码可以通畅的进入到阻塞代码. 一个简单的例子,假设我们想开发一个流式API,之前存在的业务逻辑代码(process_orders)需要一个迭代器.通过gevent,和远程服务器交互过程中,我们可以异步的流化迭代器,而不需要修改代码.
另一个优势是,在敏感的地方总可以引发异常. 和真实的线程不同,greenlet不会在任意时间暂停,于是可以使用更少的锁和互斥量.只是在原子操作过程中存在阻塞的风险的时候,需要一个互斥量. 和真实线程的另一个不同是,一个greenlet可以杀死另外一个greenlet--当greenlet下一次恢复的时候触发一个异常. 缺点坏消息:Python 3分支版本的gevent还没有开发完成.我暂未查明是否它根本不可用. 异步I/O的缺陷和其他异步I/O框架一样,gevent也有一些缺陷:
总的来说,相对于其他异步I/O框架,gevent的缺陷更少(当然,你可能不能死锁回调,这仅仅是因为,事件循环没有提供同步原始,所以你无法实现临界区). 一个gevent回避的缺陷是,你几乎不会碰到一个和异步无关的Python库--它将阻塞你的应用程序,因为纯Python库使用的是monkey patch的stdlib. n到m的并发对于事件而言,一种更具规模效应的方法是,在m个物理线程中运行n个greenlet.在Python中,我们需要进程来做到这点.在多核系统中,这增加了性能,也增加了灵活性. 这是Rust和Java在其他地方使用的模型. 使用gevent的经验我评估过gevent以及在2011提到的其他系统.Gevent无疑是胜者.虽然在性能上面没太多选择,但是gevent简化编程模型却是一个主要的卖点.不是所有的开发者,在使用生成器,闭包和回调函数的时候都处于相同的水平.但是gevent没有这个要求,你可以使用任何技术让代码更易读. 在已有的代码或与I/O无关的业务逻辑中使用gevent也是很有价值的:你可能希望,在高性能的网络应用程序和线下的批处理进程中重用某个业务逻辑库. 在接下来的18个月里面,我一直在写各种各样的网络应用程序.一个产品是名为nucleon的web服务框架,它的目标是连接RESTful JSON,PostgreSQL和AMQP,所有的都通过"绿色"驱动代码保持高伸缩性. 尽管我们需要修改代码,以非阻塞的方式使用PostgreSQL,但是gevent的mokey patching意味着纯Python驱动在其他数据存储过程中已经正常运行了--所以Redis,ElasticSearch和CouchDB都可以透明的使用. AMQP库最初是Puka (不是Pika)的一个复制, AMQP库没有强化异步的特性(像Pika一样).我最终完全重写了它,并把它单独作为一个名为nucleon.amqp的项目. nucleon.amqp允许使用完整的同步编程模型和AMQP服务器交互--AMQP的远程队列可以通过Queue API暴露在本地. 在一些并发编程的项目中,也有一些让人抓狂的时候.但是作为一个团队,我们适应了gevent,并且开发了一种图表语言.用它来向各个成员解释,理解各个greenlet之间的数据流向,相互之间如何阻塞以及如何发送信号. 这个项目成功了.我们保持代码简洁和可维护,同时也保证服务高效和可伸缩(负载测试中保留的) |