Python的twisted有干净轻量的替代品吗?
很久以前,我写了一个网络爬虫,并使用多线程来实现同时发送多个请求。那时候我还年轻,对Python的了解不多,也不知道什么是GIL,以及它给多线程代码带来的麻烦(也就是说,大多数情况下,代码最终都是串行执行的!)...
我想重新整理这段代码,让它更稳健,性能更好。基本上我有两种选择:要么使用2.6及以上版本的新multiprocessing模块,要么采用某种反应器/事件驱动的模型。我更倾向于后者,因为它更简单,出错的可能性也更小。
所以,我的问题是,哪个框架最适合我的需求。以下是我目前知道的一些选项:
- Twisted:Python反应器框架的老大,虽然看起来复杂且有点臃肿,但学习曲线很陡,做个小任务都不容易。
- Eventlet:来自lindenlab的团队。基于Greenlet的框架,专门用于这类任务。不过我看了一下代码,感觉不太好:不符合pep8标准,代码里满是打印语句(为什么框架里会有这个!?),API似乎也有点不一致。
- PyEv:还不成熟,目前似乎没有人使用,但它基于libevent,所以后端是比较稳固的。
- asyncore:来自标准库的超低级接口,感觉要做点事情需要很多准备工作。
- tornado:虽然这是一个面向服务器的产品,旨在为动态网站提供服务,但它确实有一个异步HTTP客户端和一个简单的ioloop。看起来可以完成任务,但这并不是它的初衷。[编辑:不幸的是,它在Windows上无法运行,这对我来说是个问题——我必须支持这个无奈的平台]
我有没有遗漏什么?肯定有某个库能满足我对简化异步网络库的需求吧!
[编辑:非常感谢intgr给我指向这个页面的建议。如果你滚动到页面底部,会看到一个很不错的项目列表,旨在以某种方式解决这个任务。实际上,自从Twisted诞生以来,事情确实有所进展:现在人们似乎更喜欢基于协程的解决方案,而不是传统的反应器/回调模型。这种方法的好处是代码更清晰、直接:我过去发现,尤其是在使用boost.asio进行C++开发时,基于回调的代码往往会导致设计难以理解,对没有经验的人来说相对晦涩。使用协程可以让代码看起来更像是同步的。现在我的任务是找出这些库中我喜欢哪个,然后试试看!现在问这个问题真是太好了...]
[编辑:也许对关注或偶然看到这个问题的人来说,这个话题有点意思:我找到了一篇关于可用工具现状的很棒的文章]
14 个回答
在使用上,它遵循了标准库的相同规则(特别是线程和多进程模块),这样你就能看到一些熟悉的东西,比如 队列 和 事件。
它只支持 libevent (更新: 从1.0开始也支持 libev)作为反应器的实现,但它充分利用了这个库,提供了一个基于libevent-http的快速WSGI服务器,并通过libevent-dns来解析DNS查询,而不是像大多数其他库那样使用线程池。(更新: 从1.0开始,使用c-ares来进行异步DNS查询;线程池也是一个选项。)
和eventlet一样,它通过使用 greenlets,让回调和Deferreds变得不必要。
可以看看这些例子: 同时下载多个网址, 基于Django和gevent的长轮询网页聊天。
你说得对,Twisted确实有点复杂。不过,Twisted并不是臃肿的。
如果你去看看这个链接:http://twistedmatrix.com/trac/browser/trunk/twisted,你会发现这里有很多互联网协议的整齐、全面且经过充分测试的代码,还有一些帮助你编写和部署复杂网络应用的辅助代码。我觉得不要把“臃肿”跟“全面”搞混了。
大家都知道,Twisted的文档一开始看起来不太友好,这可能让不少人望而却步。但我认为,如果你愿意花时间去学习,Twisted是非常棒的(这是我的个人看法)。我自己也花了时间去研究,结果发现真的很值得,我也建议其他人试试看。
我喜欢这个名为 concurrence 的Python模块,它使用Stackless Python的微线程或者Greenlets来实现轻量级的线程。所有阻塞的网络输入输出都通过一个单独的 libevent
循环自动变成异步的,所以它的效率几乎和真正的异步服务器一样高。
我想这和Eventlet有点像。
不过,它的接口和Python的 sockets
/ threading
模块差别挺大;你可能需要重写不少代码(或者写一个兼容层)来适应它。
编辑: 似乎还有一个叫 cogen 的东西,它也很相似,但使用的是Python 2.5的 增强生成器 来实现协程,而不是Greenlets。这让它比concurrence和其他选择更具可移植性。网络输入输出是直接通过epoll/kqueue/iocp来处理的。