本文介绍了asyncio和trio之间的核心区别是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

今天,我发现了一个名为 trio 的库,它说自己是异步的适用于人类的API.这些词与requests'有点类似.由于requests确实是一个很好的库,所以我想知道trio的优点是什么.

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

在阅读了文章的一半之后,我找不到这两个异步框架之间的核心区别.仅举例说明curio的实现比asyncio的实现更方便.但是底层结构几乎是相同的(基于回调,我认为所有异步IO框架都基于回调而没有任何异常.)

那么有人可以给我一个理由,我必须接受triocurioasyncio好吗?或解释更多有关为什么我应该选择trio而不是内置的asyncio的信息?

解决方案

我来自哪里:我是trio的主要作者.我还是curio的主要贡献者之一(并撰写了您链接到该文章的文章),并且是一名Python核心开发人员,他一直积极参与有关如何改进asyncio的讨论.

我不确定您对回调的含义.在trio(和curio)中,核心设计原则之一是永远不要使用回调进行编程.与基于回调的编程相比,它更像是基于线程的编程.我猜想,如果您打开引擎盖,看看它们是如何在内部实现的,那么在某些地方,它们会使用回调,或者如果您斜视,它们在某种程度上等效于回调.但这就像说Python和C是等效的,因为Python解释器是用C实现的.从不使用回调.

无论如何:

Trio vs asyncio

Asyncio更成熟

第一个大差异是生态系统的成熟度.当我在 2018年3月撰写本文时,与异步支持相比,支持异步的库多了[em> 个.例如,目前还没有任何真正的具有三重奏支持的HTTP服务器. PyPI上的 Framework :: AsyncIO分类器当前具有122个库,而 Framework :: Trio分类器只有8.我希望答案的这一部分会很快过时–例如,这里是肯尼思·雷兹(Kenneth Reitz)尝试添加三重奏在下一版本的请求中提供支持 –但是现在,您应该期望,如果您对复杂的事情感到三重,那么您将遇到需要自己填写的缺失部分,而不是从中获取库pypi,或者您需要使用 trio-asyncio软件包,该软件包可让您在三重奏程序中使用asyncio库. (三重聊天频道对于了解可用内容以及其他人正在从事的工作很有用. )

Trio使您的代码更简单

就实际的库而言,它们也有很大的不同. trio的主要论点是,与使用asyncio相比,它使编写并发代码更加简单.当然,当您最后一次听到有人说他们的图书馆使事情变得更难使用时,...让我举一个具体的例子.在此演讲(幻灯片),我使用实现 RFC 8305高兴的眼球" ,这是一种用于有效建立网络连接的简单并发算法.这是 Glyph 多年来一直在思考的问题,而他最新的Twisted版本大约有600行. (Asyncio大致相同; Twisted和asyncio在架构上非常相似.)在演讲中,我教给您使用Trio在少于40行中实现它所需的一切知识(并且我们在修复他的版本中的一个错误时,在).因此,在此示例中,从字面上使用trio可使我们的代码简化一个数量级.

您可能还会发现来自用户的以下评论很有趣: 1 2 3

细节上有很多不同

为什么会这样?那是一个更长的答案:-).我正在逐步致力于在博客文章和讲座中撰写不同的文章,并且我会尽量记住在链接可用时使用链接更新此答案.基本上,归结为Trio具有少量精心设计的基元,这些基元与我所知的任何其他库都有一些基本差异(尽管当然是基于很多地方的思想).以下是一些随机注释,可让您有所了解:

在异步和相关库中,一个非常非常普遍的问题是您调用了some_function(),它返回了,所以您认为它已经完成了-但实际上它仍在后台运行.这会导致各种棘手的错误,因为这使得很难控制事情发生的顺序,或者很难知道什么时候实际完成,并且可以直接隐藏问题,因为如果后台任务因未处理的异常而崩溃,那么asyncio将通常只需在控制台上打印一些内容,然后继续操作即可.在trio中,我们通过"nurseries"处理任务生成的方式意味着这些事情都不会发生:当一个函数返回时,您就知道它已经完成了,并且Trio是当前唯一的Python并发库,在该库中,异常总是一直传播到被捕获./p>

Trio的超时和取消管理方式很新颖,我认为比以前的最新系统(例如C#和Golang)要好. 我实际上确实写了整篇文章,所以我不会不要在这里详细介绍所有细节.但是asyncio的取消系统(或者说,实际上,它具有两个语义稍有不同的系统)基于一套比C#和Golang更旧的思想,并且很难正确使用. (例如,代码很容易通过生成后台任务意外地逃避"取消;请参见上一段.)

asyncio中有很多冗余的 stuff 很难做到告诉何时使用哪个东西.您拥有期货,任务和协程,它们基本上都用于相同的目的,但是您需要了解它们之间的区别.如果要实现网络协议,则必须选择是使用协议/传输层还是流层,它们都具有棘手的陷阱(这是您链接的文章是的内容.

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

总结

如果您需要在下周将某些产品交付生产,则应使用asyncio(或Twisted或Tornado或gevent,它们甚至更成熟).它们拥有庞大的生态系统,其他人在您使用之前已将其用于生产,而且它们无处可走.

如果尝试使用这些框架会让您感到沮丧和困惑,或者想尝试一种不同的做事方式,那么肯定要试试三重奏-我们很友好:-).

如果您想从现在开始一年内将某些产品交付生产……那么我不确定该告诉您什么. Python并发性在不断变化. Trio在设计级别上具有许多优势,但是是否足以克服asyncio的领先优势?将异步存储在标准库中是有利还是不利? (请注意,尽管标准库具有 urllib .)可以在asyncio中添加三重奏中的多少个新想法?没人知道.我希望今年在PyCon上会有很多有趣的讨论:-).

Today, I found a library named trio which says itself is an asynchronous API for humans. These words are a little similar with requests'. As requests is really a good library, I am wondering what is the advantages of trio.

There aren't many articles about it, I just find an article discussing curio and asyncio. To my surprise, trio says itself is even better than curio(next-generation curio).

After reading half of the article, I cannot find the core difference between these two asynchronous framework. It just gives some examples that curio's implementation is more convenient than asyncio's. But the underlying structure is almost the same(callback-based, I think all asynchronous IO framework are based on callback without any exception.)

So could someone give me a reason I have to accept that trio or curio is better than asyncio? Or explain more about why I should choose trio instead of built-in asyncio?

解决方案

Where I'm coming from: I'm the primary author of trio. I'm also one of the top contributors to curio (and wrote the article about it that you link to), and a Python core dev who's been heavily involved in discussions about how to improve asyncio.

I'm not sure what you mean about callbacks. In trio (and curio), one of the core design principles is that you never program with callbacks; it feels more like thread-based programming than callback-based programming. I guess if you open up the hood and look at how they're implemented internally, then there are places where they use callbacks, or things that are sorta equivalent to callbacks if you squint. But that's like saying that Python and C are equivalent because the Python interpreter is implemented in C. You never use callbacks.

Anyway:

Trio vs asyncio

Asyncio is more mature

The first big difference is ecosystem maturity. At the time I'm writing this in March 2018, there are many more libraries with asyncio support than trio support. For example, right now there aren't any real HTTP servers with trio support. The 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 is useful for finding out about what's available, and what other people are working on.)

Trio makes your code simpler

In terms of the actual libraries, they're also very different. The main argument for trio is that it makes writing concurrent code much, much simpler than using asyncio. Of course, when was the last time you heard someone say that their library makes things harder to use... let me give a concrete example. 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 has been thinking about for years, and his latest version for Twisted is ~600 lines long. (Asyncio would be about the same; Twisted and asyncio are very similar architecturally.) In the talk, I teach you everything you need to know to implement it in <40 lines using trio (and we fix a bug in his version while we're at it). So in this example, using trio literally makes our code an order of magnitude simpler.

You might also find these comments from users interesting: 1, 2, 3

There are many many differences in detail

Why does this happen? That's a much longer answer :-). I'm gradually working on writing up the different pieces in blog posts and talks, and I'll try to remember to update this answer with links as they become available. Basically, it comes down to Trio having a small set of carefully designed primitives that have a few fundamental differences from any other library I know of (though of course build on ideas from lots of places). Here are some random notes to give you some idea:

A very, very common problem in asyncio and related libraries is that you call some_function(), and it returns, so you think it's done – but actually it's still running in the background. This leads to all kinds of tricky bugs, because it makes it difficult to control the order in which things happen, or know when anything has actually finished, and it can directly hide problems because if a background task crashes with an unhandled exception, asyncio will generally just print something to the console and then keep going. In trio, the way we handle task spawning via "nurseries" means that none of these things happen: when a function returns then you know it's done, and Trio's currently the only concurrency library for Python where exceptions always propagate until you catch them.

Trio's way of managing timeouts and cancellations is novel, and I think better than previous state-of-the-art systems like C# and Golang. I actually did write a whole essay on this, so I won't go into all the details here. But asyncio's cancellation system – or really, systems, it has two of them with slightly different semantics – are based on an older set of ideas than even C# and Golang, and are difficult to use correctly. (For example, it's easy for code to accidentally "escape" a cancellation by spawning a background task; see previous paragraph.)

There's a ton of redundant stuff in asyncio, which 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 is about).

Trio's currently the only concurrency library for Python where control-C just works the way you expect (i.e., it raises KeyboardInterrupt where-ever your code is). It's a small thing, but it makes a big difference :-). For various reasons, I don't think this is fixable in asyncio.

Summing up

If you need to ship something to production next week, then you should use asyncio (or Twisted or Tornado or gevent, which are even more mature). They have large ecosystems, other people have used them in production before you, and they're not going anywhere.

If trying to use those frameworks leaves you frustrated and confused, or if want to experiment with a different way of doing things, then definitely check out trio – we're friendly :-).

If you want to ship something to production a year from now... then I'm not sure what to tell you. Python concurrency is in flux. Trio has many advantages at the design level, but is that enough to overcome asyncio's head start? Will asyncio being in the standard library be an advantage, or a disadvantage? (Notice how these days everyone uses requests, even though the standard library has urllib.) How many of the new ideas in trio can be added to asyncio? No-one knows. I expect that there will be a lot of interesting discussions about this at PyCon this year :-).

这篇关于asyncio和trio之间的核心区别是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-10 08:30