Asyncio vs. Gevent
我曾经在一个python2系统上工作过,这个系统有很多自定义的I/O代码是同步编写的,并且使用线程进行缩放。在某种程度上,我们无法进一步扩展它,并且意识到我们必须切换到异步编程。
- 扭曲是流行的选择,但我们想避免它的回调地狱。
- 它确实有
@inlineCallbacks 装饰器,它和其他一些库一样,使用generator magic有效地实现协程。这是可以容忍的,但感觉有点不对劲。 - 然后我们找到了Gevent。你所要做的就是:
1 2 | from gevent import monkey monkey.patch_all() |
就像这样,所有的标准I/O——套接字、数据库事务、所有用纯Python编写的东西——都是异步的,使用greenlet在后台生成和切换。
它并不完美:
- 当时,它在Windows上运行得不好(现在它仍然有一些限制)。幸运的是,我们在Linux上运行。
- 它不能猴补丁C扩展,所以我们不能使用mysqldb,例如。幸运的是,有很多纯python替代品,比如pymysql。
问题
现在,python 3更受欢迎,并且与它一起使用——asyncio。就我个人而言,我认为这很好,但最近有人问我,这比我们对Gevent所做的更好吗,我想不出一个足够好的答案。
这听起来可能是主观的,但我实际上在寻找真正的用例,其中一个会显著优于另一个,或者允许另一个不允许的东西。以下是迄今为止我收集到的注意事项:
就像我说的,gevent在窗户上相当有限。另外,我所知道的大多数生产代码都在Linux上运行。
如果需要在Windows上运行,请使用Asyncio。
gevent不能猴补丁C扩展。但是,Asyncio不能猴子修补任何东西。
假设出现了一种新的数据库技术,您希望使用它,但是没有一个纯粹的Python库,所以您不能将它与gevent集成。问题是,当没有可以与Asyncio集成的IO*库时,您就陷入了困境!当然,也有工作线程和执行器,但这不是重点,而且在这两种情况下都工作得很好。
有些人说这是个人爱好的问题,但我认为可以公平地说,同步编程本质上比异步编程更容易(想想看:你有没有遇到过一个可以使用套接字的初学者,但是很难理解如何正确地选择/轮询它们,或者思考未来/承诺?你见过反面吗?).
不管怎样,我们不要去那里。我想解决这一点,因为它经常出现(这里有一个关于reddit的讨论),但我真正想要的是场景,其中你有一个实际的理由使用其中一个。
Asyncio是标准库的一部分。这是巨大的:这意味着它得到了很好的维护,有很好的文档记录,并且每个人都知道它,并且在默认情况下使用它。
但是,考虑到使用gevent所需的知识很少(而且它也得到了很好的维护和文档记录),它似乎没有那么重要。因此,尽管在StackOverflow上有多个关于期货的最复杂场景的答案,但根本不使用期货的可能性似乎同样可行。
那么:异步盛行的一些具体用例是什么?毫无疑问,guido和python社区有充分的理由投入这么多精力,甚至在语言中引入新的关键字——我似乎找不到它们。
实际使用的"简单"答案:
我认为,以后的观点才是关键。在软件工程中,最被低估的是代码是要被读取的,而不是有效地编写或运行的(如果以后是这样的话,那么您宁愿从Python转换到系统级语言)。Asyncio缺少用于异步编程的部分-预定义的和控制的上下文切换点。您实际上编写了同步代码(即不考虑突然的线程切换、锁、队列等),并且在知道调用是IO阻塞时使用
这就是Asyncio如此优秀的原因——它很容易维护。缺点是几乎所有的"世界"都必须是异步的——DB驱动程序、HTTP工具、文件处理程序。有时你会错过图书馆,这是很有保证的。