ChatGPT解决这个技术问题 Extra ChatGPT

一个干净、轻量级的 Python 扭曲替代品? [关闭]

关闭。此问题不符合 Stack Overflow 准则。它目前不接受答案。我们不允许提出有关书籍、工具、软件库等建议的问题。您可以编辑问题,以便可以用事实和引用来回答它。 7年前关闭。改进这个问题

A(很久以前)我写了一个多线程的网络蜘蛛,以使并发请求能够同时发生。那是在我的 Python 青年时代,在我了解 GIL 及其为多线程代码(IE,大多数时候东西最终都被序列化!)带来的相关问题之前的日子......

我想重新编写此代码以使其更健壮且性能更好。基本上有两种方法可以做到这一点:我可以使用 2.6+ 中的新 multiprocessing module 或者我可以使用某种基于反应器/事件的模型。我宁愿做后者,因为它更简单且不易出错。

因此,问题与哪种框架最适合我的需求有关。以下是我目前所知道的选项列表:

Twisted:Python 反应器框架的鼻祖:看起来很复杂而且有点臃肿。小任务的陡峭学习曲线。

Eventlet:来自 lindenlab 的人。面向此类任务的基于 Greenlet 的框架。不过,我查看了代码,它不太漂亮:不符合 pep8,散布着打印(为什么人们在框架中这样做!?),API 似乎有点不一致。

PyEv:不成熟,现在似乎没有人在使用它,虽然它是基于 libevent 的,所以它有一个可靠的后端。

asyncore:来自 stdlib:über 低级,似乎需要大量的跑腿工作才能使某些东西脱离实际。

tornado:虽然这是一个面向服务器的产品,旨在为动态网站提供服务,但它确实具有异步 HTTP 客户端和简单的 ioloop。看起来它可以完成工作,但不是它的预期目的。 [编辑:不幸的是,它不能在 Windows 上运行,这对我来说很重要——我需要支持这个蹩脚的平台]

有什么我错过的吗?当然,必须有一个适合简化异步网络库的最佳位置的库!

[编辑:非常感谢 intgr 指向 this page。如果您滚动到底部,您会看到一个非常好的项目列表,旨在以一种或另一种方式解决此任务。实际上,自从 Twisted 成立以来,事情似乎确实在发生变化:人们现在似乎更喜欢基于 co-routine 的解决方案,而不是传统的面向反应器/回调的解决方案。这种方法的好处是代码更清晰更直接:我过去确实发现,尤其是在使用 C++ 中的 boost.asio 时,基于回调的代码可能会导致设计难以遵循并且相对晦涩难懂未经训练的眼睛。使用协同例程可以让你编写至少看起来更同步的代码。我想现在我的任务是找出我喜欢这些库中的哪个外观并试一试!很高兴我现在问...]

[编辑:也许任何关注或偶然发现这个问题或在任何意义上关心这个话题的人都会感兴趣:我为这项工作找到了一篇关于 the available tools 当前状态的非常棒的文章]

Python 是多线程的,它只是不允许两个线程同时运行 Python 代码。
我从你的问题中学到的比从答案中学到的要多得多。
@Denis:呵呵,谢谢!答案中也有一些很好的指示,特别是 intgr。我知道那里有很多选择,我不只是想要这些答案,所以我想我会不厌其烦地拼出我所知道的:)
> 人们现在似乎更喜欢基于协同程序的解决方案,而不是传统的面向反应器/回调的解决方案。这不是一个明智的比较。 “基于协同程序的解决方案”和“面向反应器”的解决方案是正交的。 (忽略 Python 没有协程的事实)看看 Twisted 的 inlineCallbacks,看看如何通过健壮、成熟的网络层拥有您似乎更喜欢的编程风格,不会让您接触到复杂的平台特质。
补充几点: 1. Tornado 在 Windows 上运行良好。它的性能和可扩展性不高,因为它使用 select 进行 I/O 多路复用。但是您应该能够使用 tornado-pyuv 从中获得不错的性能。 2. Python 3.3+ 和它的 backport trollius 现在有 asyncio,它允许在其事件循环中运行任何 Tornado 应用程序(很快将支持 Twisted)。

c
clemesha

Twisted 很复杂,你说得对。 Twisted 不臃肿。

如果您在此处查看:http://twistedmatrix.com/trac/browser/trunk/twisted 您会发现一个有组织、全面且经过良好测试的互联网许多协议套件,以及用于编写和部署非常复杂的网络的帮助代码应用程序。我不会将臃肿与全面性混为一谈。

众所周知,Twisted 文档乍一看并不是最友好的,我相信这会让很多不幸的人望而却步。但是如果你投入时间,Twisted 是惊人的(恕我直言)。我做到了,事实证明这是值得的,我建议其他人也尝试一下。


@clemesha:也许你是对的,它并没有被加载,但我确实觉得做一些简单的事情有点太多了。我了解异步编程,我曾在 C++ 中使用 boost::asio 工作过,所以这些概念并不新鲜,但它与做扭曲的东西相得益彰:这是一个全新的世界,就像 django 用于网络东西一样。同样,当我在做 Web 工作时,我使用轻量级 WSGI 代码并只将我需要的东西组合在一起。我猜是课程的马。
@clemesha:呃,我今天冒险看看:twisted 有 20MB!甚至核心是 12MB....如果这不是臃肿,我不确定是什么。
基本的 Twisted API 非常小(反应堆、延迟、协议)。大多数 Twisted 代码是使用这些基础的异步协议实现。 “膨胀”在这里(或者实际上在大多数情况下)不是一个有用的形容词。 Twisted 的大小对于它所做的事情的数量来说是合理的。
N
Noumenon

geventeventlet cleaned up

在 API 方面,它遵循与有意义的标准库(特别是线程和多处理模块)相同的约定。因此,您可以使用熟悉的东西,例如 QueueEvent

它仅支持 libevent (update: libev since 1.0) 作为反应器实现,但充分利用了它,具有基于 libevent-http 的快速 WSGI 服务器并通过 libevent-dns 解析 DNS 查询而不是像大多数其他库一样使用线程池。 (更新: 因为 1.0 c-ares 用于进行异步 DNS 查询;线程池也是一个选项。)

与 eventlet 一样,它通过使用 greenlets 使回调和 Deferred 变得不必要。

查看示例:concurrent download of multiple urlslong polling webchat


我会第二个 gevent -- 在查看了许多解决方案之后,gevent 对我来说工作得很好。它使我能够保留现有程序的大部分内容,并且所需的更改是微不足道的——最重要的是,如果代码需要在 3、4、5、... 年的时间内维护,它仍然可以对于任何不熟悉 gevent 的人来说,Twisted 最大的亮点是强大的学习曲线,这不仅会在实施时造成问题,而且在维护期间也会导致问题......
i
intgr

我喜欢 concurrence Python 模块,它依赖于 Stackless Python 微线程或 Greenlets 来实现轻量级线程。所有阻塞网络 I/O 都通过一个 libevent 循环透明地异步化,因此它应该几乎与真正的异步服务器一样高效。

我想它在这种方式上类似于 Eventlet。

缺点是它的 API 与 Python 的 sockets/threading 模块有很大不同;您需要重写相当多的应用程序(或编写兼容性 shim 层)

编辑:似乎还有 cogen,它是类似的,但它的协程使用 Python 2.5 的增强型生成器,而不是 Greenlets。这使得它比并发和其他替代方案更便携。网络 I/O 直接使用 epoll/kqueue/iocp 完成。


@intgr:很棒的链接。我以前曾见过这两个,这些都是我希望看到的东西。 +1
看起来并发是一个死项目,他们是四年前的最后一次更新。
项目已经死了,Hyves 也死了!
自 Python 2.5 以来发生了很多事情。 Python 3.5 中的 asyncio 很棒。
j
jkp

Nicholas Piël 在他的博客上编译了真正interesting comparison的此类框架:非常值得一读!


虽然我同意这篇文章读起来很有趣,但我认为值得考虑所提供基准的有效性。请参阅此处的评论:reddit.com/r/programming/comments/ahepg/…
@clemesha,虽然该 reddit 页面中的点值得注意,但基准测试是在双核机器上完成的,并且可能没有遭受所描述的致命缺陷。我想客户端和服务器可能都在同一个核心上运行,但似乎不太可能。
A
Adam Hupp

这些解决方案都不能避免 GIL 阻止 CPU 并行性这一事实——它们只是获得线程已经拥有的 IO 并行性的更好方法。如果你认为你可以做更好的 IO,一定要追求其中之一,但如果你的瓶颈在于处理结果,除了多处理模块之外,这里没有任何帮助。


使用多个进程有什么问题?
什么都没有,因此建议使用多处理模块。
r
rhettg

我不会说 Twisted 臃肿,但很难缠住你的头。很长一段时间以来,我一直避免真正沉迷于学习中,因为我一直希望“小任务”更容易一些。

但是,既然我已经使用它更多了,我不得不说包含所有电池非常好。

我使用过的所有其他异步库最终都没有它们看起来那么成熟。 Twisted 的事件循环是可靠的。

我不太确定如何解决陡峭的 Twisted 学习曲线。如果有人将它分叉并清理一些东西可能会有所帮助,例如删除所有向后兼容的垃圾和死项目。但我猜这就是成熟软件的本质。


如果您曾经查看过 gtk 反应器是如何在 Windows 下实现的(每 10 毫秒进行一次硬核轮询:twistedmatrix.com/trac/browser/trunk/twisted/internet/…),您就不会称其为“成熟”...
嗨@schlamar。这个讨厌的 hack 是作为 GTK+ 中一些非常严重的错误的解决方法而实施的,当时人们对电源效率的担忧要少得多:)。但是,Twisted 的美妙之处在于我们可以一次 处理这个错误,然后在框架中修复它,我们的用户不需要担心它。您愿意提供解决此问题并摆脱(弃用然后删除)PortableGtkReactor 的修复程序吗?
@Glyph 如果其他人想解决此问题,我在 twistedmatrix.com/trac/ticket/4744#comment:2 上添加了有用的建议,因为其中一些问题仍然存在。顺便说一句,您可以通过在两个事件循环之间安排回调来更有效地解决这个问题。
S
Steven Kryskalla

Kamaelia 尚未提及。它的并发模型基于将组件连接在一起,并在收件箱和发件箱之间传递消息。 Here 的简要概述。


我将 kamaelia 用于应用程序 - 这非常痛苦。恕我直言,python 中还有其他更好的并发选项(其中大部分都在上面提到过)
F
Flexo

我已经开始在某些事情上使用twisted。它的美丽几乎是因为它“臃肿”。几乎所有主要协议都有连接器。你可以有一个 jabber bot,它会接受命令并发布到 irc 服务器,通过电子邮件将它们发送给某人,运行命令,从 NNTP 服务器读取,并监视网页的更改。坏消息是它可以完成所有这些工作,并且对于像 OP 解释的简单任务而言,它会使事情变得过于复杂。不过,python 的优点是你只包含你需要的东西。因此,虽然下载可能是 20mb,但您可能只包含 2mb 的库(这仍然很多)。我对 twisted 最大的抱怨是,尽管它们包含示例,但除了您自己的基本 tcp 服务器之外的任何内容。

虽然不是 python 解决方案,但我已经看到 node.js 最近获得了更多的吸引力。事实上,我已经考虑过为较小的项目研究它,但当我听到 javascript 时我只是畏缩 :)


我是 Python 的忠实粉丝。 – 查看 Douglas Crockford 的“Javascript – The good parts”(3、4 个视频)。看看 CoffeeScript。事实证明 JS 有 Python 应该有的东西,除了语法,哈哈。 CS试图减轻这种情况,但在这方面有点笨拙......
m
mrsmoothie

关于这个主题有一本好书:Abe Fettig 的“Twisted Network Programming Essentials”。这些示例展示了如何编写非常 Pythonic 的代码,对我个人而言,不要觉得我基于一个臃肿的框架。看书上的解决方案,如果不干净,那我就不知道干净是什么意思了。

我唯一的谜团和其他框架一样,比如 Ruby。我担心,它会扩大吗?我不愿意将客户提交给会出现可伸缩性问题的框架。


b
bfrog

Whizzer 是一个使用 pyev 的小型异步套接字框架。它非常快,主要是因为 pyev。它试图提供一个类似的界面,就像扭曲了一些细微的变化一样。


p
pts

也试试 Syncless。它是基于协程的(所以它类似于 Concurrence、Eventlet 和 gevent)。它实现了对 socket.socket、socket.gethostbyname(等)、ssl.SSLSocket、time.sleep 和 select.select 的插入式非阻塞替换。它很快。它需要 Stackless Python 和 libevent。它包含一个用 C (Pyrex/Cython) 编写的强制性 Python 扩展。


R
Robert Zaremba

我确认 syncless 的优点。它可以使用 libev(更新、更干净、性能更好的 libevent 版本)。前段时间它没有像 libevent 那么多的支持,但现在开发过程更加先进并且syncless非常有用。


e
ejectamenta

如果您只想要一个简化的、轻量级的 HTTP 请求库,那么我发现 Unirest 非常好


r
renejsum

欢迎您查看 PyWorks,它采用了完全不同的方法。它允许对象实例在它们自己的线程中运行,并使对该对象的函数调用异步。

只要让一个类继承自Task而不是object,它是异步的,所有方法调用都是Proxies。返回值(如果您需要它们)是未来代理。

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 上找到


虽然这很有趣并且可能适用于某些任务,但使用线程进行网络连接性能不佳(尤其是在 Python 上,由于 GIL)。这正是问题所在:事件框架或多处理。所以你的答案显然超出了范围......