A clean, lightweight alternative to Python's twisted?
不久前,我写了一个Web蜘蛛,我多线程处理它,使并发请求能够同时发生。那是在我的python青年时代,在我了解gil和它为多线程代码所造成的相关灾难(即,大多数时间都是序列化的!)…
我想重新编写这段代码,使其更健壮,性能更好。基本上有两种方法可以做到这一点:我可以在2.6+中使用新的多处理模块,或者我可以使用某种基于反应堆/事件的模型。我宁愿晚一点做,因为它要简单得多,而且不容易出错。
所以问题是什么框架最适合我的需要。以下是迄今为止我所知道的选项列表:
- Twisted:python reactor框架的祖宗:看起来很复杂,但是有点臃肿。小任务的陡峭学习曲线。
- 事件:来自Lindenlab的人。面向这些任务的基于greenlet的框架。不过,我看了一下代码,它不太漂亮:不符合PEP8标准,分散了一些印刷品(为什么人们要在框架中这样做!)?),API有点不一致。
- 皮耶夫:不成熟,目前似乎没有人使用它,尽管它是基于libevent的,所以它有一个坚实的后端。
- Asyncore:从stdlib:_ber的底层来看,这似乎是为了让一些东西离开地面而进行的大量立法工作。
- Tornado:虽然这是一个面向服务器的产品,旨在为动态网站提供服务,但它具有一个异步HTTP客户端和一个简单的IOLoop。看起来它能完成任务,但不能完成它的预期目标。[编辑:不在Windows上运行很不幸,这对我来说很重要-这是我支持这个跛脚平台的要求]
有什么我错过的吗?当然,那里一定有一个适合简化异步网络库的最佳位置的库!
[编辑:非常感谢Intgr提供了指向此页面的指针。如果滚动到底部,您将看到一个非常好的项目列表,这些项目旨在以某种方式处理此任务。事实上,自从Twisted的诞生以来,事情确实发生了变化:人们现在似乎更喜欢基于共同程序的解决方案,而不是传统的面向反应堆/回调的解决方案。这种方法的好处是更明确的更直接的代码:我在过去找到了,特别是在使用BooSt.Asio在C++中,基于回调的代码可以导致难以遵循的设计,对未受过训练的眼睛来说是相对模糊的。使用协同例程可以编写看起来更为同步的代码。我想现在我的任务是找出我喜欢这些图书馆中的哪一个,并尝试一下!很高兴我现在问……]
[编辑:任何跟踪或偶然发现此问题或在任何意义上关心此主题的人都可能感兴趣:我发现了有关此工作可用工具的当前状态的非常好的书面记录]
扭曲是复杂的,你说得对。扭曲不是膨胀。
如果你看一下这里:http://twistedmatrix.com/trac/browser/trunk/twisted,你会发现一套有组织的、全面的、经过良好测试的互联网协议套件,以及编写和部署非常复杂的网络应用程序的辅助代码。我不会把膨胀和全面性混淆。
众所周知,从第一眼看,扭曲的文档并不是最容易使用的,我相信这会让很多人失望。但是如果你投入时间的话,扭曲是惊人的。我做到了,结果证明这是值得的,我建议其他人也这么做。
gevent是eventlet清理。
在API方面,它遵循与标准库(特别是线程和多处理模块)相同的约定,这是有意义的。所以,您有一些熟悉的事情,比如队列和要处理的事件。
它只支持libevent(更新:libev自1.0以来)作为reactor实现,但充分利用了它,它具有一个基于libevent http的快速wsgi服务器,并通过libevent dns解析dns查询,而不像大多数其他库那样使用线程池。(更新:因为1.0c-ares用于进行异步DNS查询;threadpool也是一个选项。)
和eventlet一样,它通过使用greenlet使回调和延迟变得不必要。
查看示例:并发下载多个URL、长轮询网络聊天。
NicholasPi对这些框架进行了非常有趣的比较?在他的博客上:值得一读!
我喜欢concurrency python模块,它依赖于无堆栈的python微线程或轻量级线程的greenlet。所有阻塞的网络I/O都是通过单个
我想这和Eventlet类似。
缺点是它的API与python的
编辑:看起来还有Cogen,类似的,但它使用了Python2.5的增强型生成器作为协程,而不是greenlets。这使得它比并发和其他替代方案更易于移植。网络I/O直接通过epoll/kqueue/iocp完成。
这些解决方案都不能避免这样一个事实,即gil阻止了CPU并行性——它们只是获得IO并行性的更好方法,而这正是您已经拥有的线程的方法。如果你认为你可以做得更好的IO,那么一定要追求其中的一个,但是如果你的瓶颈是处理结果,那么除了多处理模块之外,这里没有什么能帮助你。
我不想说得太夸张,但很难把你的头包起来。我很长一段时间没有真正适应学习,因为我一直希望"小任务"能更容易一些。
不过,既然我已经做了更多的工作,我不得不说把所有的电池都包括在内是非常好的。
我处理过的所有其他异步库最终都没有它们看起来那么成熟。Twisted的事件循环是实心的。
我不太清楚如何解决陡峭的扭曲学习曲线。如果有人把它分给别人并清理一些东西,比如删除所有向后兼容的cruft和死掉的项目,可能会有所帮助。但我想这就是成熟软件的本质。
Kamaelia还没有被提及。它的并发模型基于将组件连接在一起,并在收件箱和发件箱之间传递消息。下面是一个简短的概述。
我开始用Twisted做一些事情。它的优点几乎是因为它是"膨胀的",在那里几乎有任何主要协议的连接器。你可以有一个Jabber机器人,它可以接收命令并发布到IRC服务器,通过电子邮件发送给某人,运行命令,从NNTP服务器读取命令,并监视网页的更改。坏消息是,它可以做到所有这些,并可以使事情过于复杂的简单任务,如OP解释。但是,Python的优点是只包含您需要的内容。因此,虽然下载可能是20MB,但您可能只包含2MB的库(这仍然是一个很大的库)。我对Twisted最大的抱怨是,尽管它们包括了一些例子,但除了基本的TCP服务器之外,您还可以自己使用。
虽然不是Python解决方案,但我已经看到node.js最近获得了更多的吸引力。事实上,我曾经考虑过在小型项目中寻找它,但当我听到javascript时,我只是畏缩了一下。
Whizzer是一个使用Pyev的小型异步套接字框架。它非常快,主要是因为皮耶夫。它试图提供一个类似于扭曲的界面,但有一些细微的变化。
有一本关于"扭曲的网络编程要领"的好书,作者是AbeFettig。这些例子说明了如何编写非常pythonic的代码,对我个人来说,不要让我觉得这是基于一个膨胀的框架。看看书中的解决方案,如果它们不干净,那么我不知道干净意味着什么。
我唯一的谜团和其他框架一样,比如Ruby。我担心,它会扩大吗?我不愿意将客户机提交到一个会出现可伸缩性问题的框架中。
我确认无向心的好处。它可以使用libev(libevent的更新、更干净、性能更好的版本)。以前它没有libevent那么多的支持,但现在开发过程更深入,非常有用。
也可以尝试无同步。它是基于协程的(所以类似于Concurrency、Eventlet和Gevent)。它实现了对socket.socket、socket.gethostbyname(等等)、ssl.sslsocket、time.sleep和select.select的非阻塞替换。它很快。它需要无堆栈的python和libevent。它包含用C(pyrex/cython)编写的强制python扩展。
如果您只想要一个简化的、轻量级的HTTP请求库,那么我觉得Unirest非常好
欢迎您来看看Pyworks,它采用了一种完全不同的方法。它允许对象实例在自己的线程中运行,并使对该对象的函数调用异步。
只要让一个类继承自任务而不是对象,它是异步的,所有方法调用都是代理。返回值(如果需要)是未来的代理。
1 2 3 4 | res = obj.method( args ) # code continues here without waiting for method to finish do_something_else( ) print"Result = %d" % res # Code will block here, if res not calculated yet |
pyworks可以在http://bitback.org/raindog/pyworks上找到。