首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么Utf8JsonReader和ReadOnlySequence没有异步函数

为什么Utf8JsonReader和ReadOnlySequence没有异步函数
EN

Software Engineering用户
提问于 2020-04-29 18:28:10
回答 1查看 1.5K关注 0票数 2

我使用了很多Utf8Json (它非常好),但已经适应了一些较低级别的代码,并开始直接使用Utf8JsonReader

查看Utf8Json库的代码,我看到JsonSerializer.DeserializeAsync最终使用的是具有Stream.ReadAsync函数的System.IO Stream类。

看看Utf8JsonReader,它使用的是ReadOnlySequence,没有任何异步函数。

在这里,https://github.com/dotnet/runtime/issues/29906提到:

Utf8JsonReader是可重入的,因此包含附加状态的Utf8JsonReader的异步包装器可以扩展到完全同步的助手函数,该函数能够创建所需的类型并执行流读取。

请回答我的问题(谢谢您的阅读时间):

  1. 为什么一个库会异步访问内存缓冲区(Utf8Json),而另一个库将同步访问内存缓冲区(Utf8JsonReader)?
  2. 我明白异步对于长期存在的IO是有意义的,比如在网络端口或磁盘上的文件上,但是在内存中,这种开销将是有害的吗?(这就是为什么ReadOnlySequence__上没有异步函数吗?)
  3. 通过创建异步包装器,github站点上的作者意味着什么?这看起来会是什么样子?
EN

回答 1

Software Engineering用户

回答已采纳

发布于 2020-04-29 19:30:05

我是引用自GitHub问题的"op“;当首次预览System.Text.Json API时,它没有任何函数来异步使用流,因此我需要编写自己的包装器来添加该功能。

async方法不能使用许多依赖于堆栈的特性,例如out参数和堆栈分配变量(Span和co),因为async方法可能在分配和范围结束之间的某个点产生结果。但是,async方法可以自由地调用一个常规的非async方法,该方法可以自由地使用这些特性,因为在执行助手函数的过程中,堆栈将保持不变。

为了满足我的需要,我首先创建了一个StreamSequence允许异步地使用Stream,但以高性能的方式将其内容输入到只有同步的Utf8JsonReader中,方法是一次以ReadOnlySequenceSegment的形式加载一个块,这个D10可以拼凑到一个ReadOnlySequence中。理论上,当JSON被消耗时,您可以在ReadOnlySequence开始时通过删除早期的ReadOnlySequenceSegment实例来回收内存页,但这还没有实现。

然后,我能够在解析流的状态机中使用它,核心async API函数使用StreamSequence一次从流加载一部分JSON内容,并将其传递给一个专用(私有)非async函数,该函数负责将ReadOnlySequence的内容解析为JSON并将其序列化到我需要的类型。这是从实现中删除的代码。,我从来没想过让它变得更一般,或者把它清理干净,因为生活阻碍了我。(我想做这个回复,但可能需要一两个月才能发帖,所以这可能更好。)

这都是基于STJ预览6的,API在preview7中被稍微更改为它的当前状态,部分原因可能是我当时提交的反馈,说明我发现公开的内部状态(#29906#29911)是多么的混乱,但概念仍然相同。您甚至可以安装STJ的preview6版本来处理这段代码,然后按照您想要的方式运行它之后,就可以升级到最新的版本并修复损坏。在所有情况下,我认为创建一个同步助手方法来从异步入口点执行工作应该是显而易见的,以及如何在这个同步上下文中自由地使用Span和co。

请注意,当前版本的STJ实际上提供了一个DeserializeAsync方法,我实际上已经用它替换了所有代码,因为我对自定义反序列化的需求并没有超过好处(在我编写这篇文章时没有异步STJ方法),但是如果您需要手动“深入”到JSON流并直接与Utf8JsonReader交互,那么您将需要一些类似的东西。

(请注意,到目前为止,我不知道我的StreamSequence可能有一个收件箱替代方案。也许更符合快速变化的ASP.NET核心API的人可以对此发表评论。)

更新使用:您可以围绕一个StreamSequence实例创建一个Stream实例,它只会将它们绑定在一起。StreamSequence.ReadMoreAsync()异步地消耗底层流中的字节,而不阻塞线程池。属性StreamSequence.Sequence公开表示流内容的ReadOnlySequence。每次对ReadMoreAsync()的后续调用都会使用另一个ReadOnlySequenceSegment扩展ReadOnlySequence,从而使更多的数据可用。您将实例化StreamSequence,读取一次,然后将StreamSequence.Sequence传递给解析器助手。如果解析器需要更多的数据来继续其操作,它应该返回一个标志,让您知道,在异步入口点上冒泡,然后可以自由地调用await ReadMoreAsync(),然后再次调用解析器继续其工作(根据需要传递任何状态信息)。

票数 6
EN
页面原文内容由Software Engineering提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://softwareengineering.stackexchange.com/questions/409479

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档