以 DRY 方式编写方法的异步版本?

问题描述 投票:0回答:1

System.IO.Stream
的文档规定,从它派生时,最多只需要实现
Read
方法。

这会自动启用在派生类型中使用

ReadAsync
方法,即 您可以免费获得异步读取

看看它是如何实现的,它非常复杂。有一个派生自 ReadWriteTask

 的自定义类 (
Task<int>
) 负责异步读取。

避免 DRY 的一种天真的方法可能如下:

public abstract class Reader { public abstract int Length { get; } public bool TryRead(Stream stream, byte[] buffer) { if (stream.Length - stream.Position < Length) { return false; } stream.ReadExactly(buffer); // do some special, lengthy stuff return true; } public async Task<bool> TryReadAsync(Stream stream, byte[] buffer) { return await Task.Run(() => TryRead(stream, buffer)).ConfigureAwait(false); } }
但是,在查看了他们的实现之后,我感觉上述方法可能是错误的/低效的。

你能建议一种模式来解决这个问题吗?

c# asynchronous design-patterns stream
1个回答
0
投票
这会自动启用在派生类型中使用 ReadAsync 方法,即您可以免费获得异步读取。

其实不然。您获得的异步读取是假异步的,这意味着它只是在线程池线程上完成的阻塞读取。所以它

看起来与调用代码异步,但它只是阻塞了不同线程。

理想情况下,如果您有一个执行实际 I/O 的

Stream

,您应该重写 
ReadAsync
 和朋友,以便它们是真正的异步实现。事实上,框架中的派生类型确实做到了这一点。

看看它是如何实现的,它是相当复杂的。有一个从 Task 派生的自定义类(ReadWriteTask)负责异步读取。

ReadWriteTask

更多的是减少/合并分配,而不是“负责异步读取”。传递给该类的委托(在线程池线程上执行)是实际执行读取操作的委托。

旁注:现代 .NET 运行时代码位于

here

避免 DRY 的一种简单方法可能如下:[异步优于同步代码]

但是,在查看了他们的实现之后,我感觉上述方法可能是错误的/低效的。

它实际上与

Stream.ReadAsync

 基本实现相同:将同步代码扔到线程池线程上。是的,您的代码和 
Stream.ReadAsync
 基本实现效率都很低。

你能建议一种模式来解决这个问题吗?

我个人的偏好是

布尔参数 hack;更现代的版本是使用通用代码生成(正如我在博客中所描述的)。

© www.soinside.com 2019 - 2024. All rights reserved.