asyncio 和 trio 的核心区别是什么?

What is the core difference between asyncio and trio?

今天,我发现了一个名为 trio 的库,它说自己是一个异步的 API 供人类使用。这些词有点像requests'。由于 requests 确实是一个很好的库,我想知道 trio.

的优点是什么

关于它的文章不多,我只是找到一个article讨论curioasyncio。令我惊讶的是,trio 说自己甚至比 curio(下一代古玩)更好。

文章看了一半,还是找不到这两个异步框架的核心区别。它只是给出了一些例子,说明 curio 的实现比 asyncio 的更方便。但是底层结构几乎是一样的。

所以有人可以给我一个理由让我不得不接受 triocurioasyncio 好吗?或者解释更多关于为什么我应该选择 trio 而不是内置的 asyncio?

我来自哪里:我是 trio 的主要作者。我也是 curio 的主要贡献者之一(并写了一篇关于它的文章,你 link ),以及 Python 核心开发人员,他积极参与有关如何改进 asyncio 的讨论。

在 trio(和 curio)中,核心设计原则之一是永远不要使用回调进行编程;感觉更像是 thread-based 编程而不是 callback-based 编程。我想如果你打开引擎盖看看它们是如何在内部实现的,那么它们在某些地方使用了回调,或者如果你眯着眼睛看的话,它们在某种程度上等同于回调。但这就像说 Python 和 C 是等价的,因为 Python 解释器是用 C 实现的。 从不使用回调。

无论如何:

Trio 与 asyncio

Asyncio 更成熟

第一个重大差异是生态系统的成熟度。我在 2018 年 3 月 写这篇文章时,支持 asyncio 的库比支持 trio 的库多很多。例如,现在没有任何真正的 HTTP 服务器支持 trio。 Framework :: AsyncIO classifier on PyPI currently has 122 libraries in it, while the Framework :: Trio classifier only has 8. I'm hoping that this part of the answer will become out of date quickly – for example, here's Kenneth Reitz experimenting with adding trio support in the next version of requests – but right now, you should expect that if you're trio for anything complicated, then you'll run into missing pieces that you need to fill in yourself instead of grabbing a library from pypi, or that you'll need to use the trio-asyncio package that lets you use asyncio libraries in trio programs. (The trio chat channel 对于了解可用的内容以及其他人正在处理的内容很有用。)

Trio 让您的代码更简单

就实际的图书馆而言,它们也有很大的不同。 trio 的主要论点是它使编写并发代码比使用 asyncio 简单得多。当然,你最后一次听到有人说他们的图书馆让事情变得更难使用是什么时候……让我举一个具体的例子。 In this talk (slides), I use the example of implementing RFC 8305 "Happy eyeballs", which is a simple concurrent algorithm used to efficiently establish a network connection. This is something that Glyph 多年来一直在思考,他的 Twisted 最新版本长约 600 行。 (Asyncio 大致相同;Twisted 和 asyncio 在架构上非常相似。)在演讲中,我会教您使用 trio 在 <40 行内实现它所需知道的一切(我们修复了他的版本中的一个错误,同时我们'重新开始)。所以在这个例子中,字面上使用 trio 使我们的代码简单了一个数量级。

您可能还会发现用户的这些评论很有趣:1, 2, 3

细节上有很多不同

为什么会这样?这是一个更长的答案:-)。我正逐渐致力于在博客文章和演讲中编写不同的部分,并且我会尽量记得在 links 可用时更新此答案。基本上,这归结为 Trio 拥有一小组精心设计的原语,这些原语与我所知道的任何其他库都有一些根本的区别(当然是建立在很多地方的想法之上)。这里有一些随机笔记可以给你一些想法:

asyncio 和相关库中一个非常非常普遍的问题是,你调用some_function(),它returns,所以你认为它完成了——但实际上它仍然是运行的背景。这会导致各种棘手的错误,因为它很难控制事情发生的顺序,或者知道什么时候真正完成,并且它可以直接隐藏问题,因为如果后台任务因未处理的异常而崩溃,asyncio 将通常只是在控制台打印一些东西然后继续。在 trio 中,我们通过“nurseries”处理任务生成的方式意味着 none 这些事情会发生:当一个函数 returns 然后你知道它已经完成,并且 Trio 目前是 [=73] 的唯一并发库=]异常总是传播直到你捕获它们。

Trio 管理超时和取消的方式很新颖,我认为比以前的 state-of-the-art 系统(如 C# 和 Golang)更好。 I actually did write a whole essay on this, 所以我不会在这里详述所有细节。但是 asyncio 的取消系统——或者实际上,系统,它有两个语义略有不同的系统——基于甚至比 C# 和 Golang 更古老的思想集,并且很难正确使用。 (例如,代码很容易通过生成后台任务意外地“逃避”取消;请参阅上一段。)

asyncio 中有大量冗余 东西can make it hard to tell which thing to use when. You have futures, tasks, and coroutines, which are all basically used for the same purpose but you need to know the differences between them. If you want to implement a network protocol, you have to pick whether to use the protocols/transports layer or the streams layer, and they both have tricky pitfalls (this is what the first part of the essay you linked 是关于)。

Trio 目前是 Python 的唯一并发库,其中 control-C 以您期望的方式工作(即,它引发 KeyboardInterrupt where-ever 您的代码)。这是一件小事,但它有很大的不同:-)。由于各种原因,我认为这在 asyncio 中无法修复。

总结

如果你需要在下周将某些东西运送到生产环境,那么你应该使用 asyncio(或者 Twisted 或 Tornado 或 gevent,它们更成熟)。他们拥有庞大的生态系统,其他人在您之前就已经在生产中使用过它们,而且他们不会去任何地方。

如果尝试使用这些框架让您感到沮丧和困惑,或者如果想尝试不同的做事方式,那么一定要看看 trio – 我们很友好 :-)。

如果您想在一年后将某些东西投入生产...那么我不知道该告诉您什么。 Python 并发性在不断变化。 Tro 在设计层面有很多优势,但这是否足以战胜 asyncio 的先机呢? asyncio 在标准库中是优势还是劣势? (注意现在每个人都使用 requests,即使标准库有 urllib。)trio 中有多少新想法可以添加到 asyncio 中? No-one知道了。我预计今年的 PyCon 上将对此进行很多有趣的讨论 :-)。