网络 - 一种干净,轻量级的Python替代方案?
很久以前我写了一个我多线程的网络蜘蛛,以便同时发生并发请求。 那是在我的Python青年时代,在我知道GIL及其为多线程代码创建的相关问题之前的几天(IE,大多数时候东西最终都被序列化了!)......
我想重做这段代码,使其更强大,性能更好。 我基本上有两种方法可以做到这一点:我可以在2.6+中使用新的多处理模块,或者我可以选择某种类型的基于反应器/事件的模型。 我宁愿做后者,因为它更简单,更不容易出错。
所以问题涉及哪种框架最适合我的需求。 以下是我目前了解的选项列表:
Twisted:Python反应器框架的祖父:看起来很复杂而且有点臃肿。 小任务的陡峭学习曲线。
Eventlet:来自lindenlab的人。 基于Greenlet的框架,适用于这些类型的任务。 我看了一下代码,但它并不太漂亮:非pep8兼容,分散打印(人们为什么要在框架中执行此操作!?),API似乎有些不一致。
PyEv:不成熟,现在似乎没有人使用它虽然它基于libevent所以它有一个坚实的后端。
asyncore:来自stdlib:über低级别,看起来很多涉及到的事情只是为了得到一些实际的东西。
龙卷风:虽然这是面向服务器的产品,旨在服务于动态网站,但它确实具有异步HTTP客户端和简单的ioloop。 看起来它可以完成工作但不是它的目的。[编辑:不幸在Windows上运行,这对我来说很重要 - 这是我支持这个蹩脚平台的要求]
我有什么遗漏吗? 当然必须有一个适合简化的异步网络库的最佳点的库!
[编辑:非常感谢intgr指向此页面的指针。 如果你滚动到底部,你会看到有一个非常好的项目列表,旨在以某种方式解决这个任务。 事实上,自Twisted开始以来事情确实已经发生了变化:人们现在似乎更倾向于基于协同例程的解决方案而不是传统的反应堆/回调导向解决方案。 这种方法的好处是更清晰,更直接的代码:我在过去肯定发现过,特别是在C ++中使用boost.asio时,基于回调的代码可能会导致难以理解的设计并且相对模糊不清 未经训练的眼睛。 使用协同例程允许您编写至少看起来更加同步的代码。 我想我现在的任务是找出我喜欢的这些库中的哪一个,并试一试! 很高兴我现在问...]
[编辑:也许对任何跟随或偶然发现这个问题或者在任何意义上关心这个话题的人都感兴趣:我发现了一个非常好的关于这个工作的可用工具的当前状态的文章]
14个解决方案
97 votes
扭曲是复杂的,你是对的。 扭曲并不臃肿。
如果你看看这里:[http://twistedmatrix.com/trac/browser/trunk/twisted]你会发现一个有组织的,全面的,经过良好测试的互联网协议套件,以及帮助代码 编写和部署非常复杂的网络应用程序。 我不会把膨胀与全面性混为一谈。
众所周知,Twisted文档从初看起并不是最方便用户的,我相信这会让一些不幸的人失望。 但如果你投入时间,扭曲是惊人的(恕我直言)。 我做了,它证明是值得的,我建议其他人尝试相同的。
clemesha answered 2019-03-01T20:24:17Z
56 votes
gevent是事件清理。
API-wise它遵循与标准库(特别是线程和多处理模块)相同的约定。 因此,您可以使用Queue和Event等熟悉的东西。
它只支持libevent(update:libev from 1.0)作为reactor实现,但充分利用它,具有基于libevent-http的快速WSGI服务器,并通过libevent-dns解析DNS查询,而不是像大多数其他库那样使用线程池 做。 (更新:因为1.0 c-ares用于进行异步DNS查询;线程池也是一个选项。)
与eventlet一样,它使用greenlet使回调和Deferred成为不必要的。
查看示例:并行下载多个URL,长轮询网聊。
Denis Bilenko answered 2019-03-01T20:25:11Z
27 votes
我喜欢并发Python模块,它依赖于Stackless Python微线程或Greenlets来实现轻量级线程。 所有阻塞网络I / O都通过单个libevent循环透明地进行异步,因此它应该与真正的异步服务器一样高效。
我想这种方式类似于Eventlet。
缺点是它的API与Python的sockets/threading模块完全不同; 你需要重写你的应用程序(或写一个兼容性填充层)
编辑:似乎还有一些类似的cogen,但是使用Python 2.5的增强型生成器来代替它的协程,而不是Greenlets。 这使得它比并发和其他替代方案更便携。 网络I / O直接使用epoll / kqueue / iocp完成。
intgr answered 2019-03-01T20:22:59Z
27 votes
NicholasPiël在他的博客上编写了一个非常有趣的比较这些框架:非常值得一读!
jkp answered 2019-03-01T20:25:35Z
15 votes
这些解决方案都不会避免GIL阻止CPU并行性这一事实 - 它们只是获得线程已经拥有的IO并行性的更好方法。 如果你认为你可以做得更好IO,那么一定要追求其中的一个,但如果你的瓶颈在于处理结果,除了多处理模块之外,这里的任何事都没有用。
Adam Hupp answered 2019-03-01T20:26:01Z
11 votes
我不会打电话给Twisted臃肿,但很难绕开你的脑袋。 我避免真正解决了很长一段时间的学习,因为我总是希望“小任务”更容易一些。
然而,现在我已经使用了它,我不得不说包含所有电池非常好。
我所使用的所有其他异步库最终都不像它们出现的那样成熟。 Twisted的事件循环是可靠的。
我不太确定如何解决陡峭的扭曲学习曲线。 如果有人将它分叉并清理一些东西,比如删除所有向后兼容性和死亡项目,这可能会有所帮助。 但我认为这就是成熟软件的本质。
rhettg answered 2019-03-01T20:26:47Z
8 votes
Kamaelia尚未被提及。 它的并发模型基于将组件连接在一起,并在收件箱和发件箱之间传递消息。 这是一个简短的概述。
Steven Kryskalla answered 2019-03-01T20:27:11Z
7 votes
我开始使用扭曲的东西。 它的美丽几乎是因为它“臃肿”。 几乎所有的主要协议都有连接器。 您可以拥有一个jabber机器人,它将接收命令并发布到irc服务器,通过电子邮件发送给某人,运行命令,从NNTP服务器读取以及监视网页以进行更改。 坏消息是,它可以做到这一切,并且可以使事情过于复杂,如OP解释的简单任务。 python的优点是你只包含你需要的东西。 因此,虽然下载量可能是20mb,但您可能只包含2mb的库(这仍然很多)。 我对twisted的最大抱怨是虽然它们包含了一些示例,但除了基本的tcp服务器之外,还有其他任何东西。
虽然不是python解决方案,但我已经看到node.js最近获得了更多的牵引力。 事实上,我已经考虑过为较小的项目进行调查但是当我听到javascript时我只是畏缩:)
vrillusions answered 2019-03-01T20:27:45Z
4 votes
有一本关于这个主题的好书:Abe Fettig撰写的“Twisted Network Programming Essentials”。 这些例子展示了如何编写非常Pythonic的代码,对我个人来说,不要基于臃肿的框架打击我。 看看书中的解决方案,如果它们不干净,那么我不知道干净意味着什么。
我唯一的谜是和其他框架一样,比如Ruby。 我担心,它会扩大规模吗? 我不想将客户端提交到一个会出现可伸缩性问题的框架。
mrsmoothie answered 2019-03-01T20:28:18Z
4 votes
Whizzer是一个使用pyev的小型异步套接字框架。 它非常快,主要是因为pyev。 它试图提供一个类似的界面扭曲与一些微小的变化。
bfrog answered 2019-03-01T20:28:48Z
2 votes
也尝试Syncless。 它是基于协程的(所以它类似于Concurrence,Eventlet和gevent)。 它实现了socket.socket,socket.gethostbyname(等),ssl.SSLSocket,time.sleep和select.select的drop-in非阻塞替换。 它很快。 它需要Stackless Python和libevent。 它包含一个用C(Pyrex / Cython)编写的强制Python扩展。
pts answered 2019-03-01T20:29:13Z
2 votes
我确认无声的好处。 它可以使用libev(libevent的更新,更清晰和更好的性能版本)。 很久以前它没有libevent那么多的支持,但现在开发过程更进一步,非常有用。
Robert Zaremba answered 2019-03-01T20:29:38Z
1 votes
如果您只想要一个简化的轻量级HTTP请求库,那么我发现Unirest非常好
ejectamenta answered 2019-03-01T20:30:04Z
0 votes
欢迎您查看PyWorks,它采用了一种完全不同的方法。 它允许对象实例在自己的线程中运行,并对该对象进行函数调用异步。
让一个类继承自Task而不是object,它是异步的,所有方法调用都是Proxies。 返回值(如果需要)是Future代理。
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://bitbucket.org/raindog/pyworks]上找到
renejsum answered 2019-03-01T20:30:54Z