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);
}
}
但是,在查看了他们的实现之后,我感觉上述方法可能是错误的/低效的。你能建议一种模式来解决这个问题吗?
这会自动启用在派生类型中使用 ReadAsync 方法,即您可以免费获得异步读取。其实不然。您获得的异步读取是假异步的,这意味着它只是在线程池线程上完成的阻塞读取。所以它
看起来与调用代码异步,但它只是阻塞了不同线程。
理想情况下,如果您有一个执行实际 I/O 的Stream
,您应该重写
ReadAsync
和朋友,以便它们是真正的异步实现。事实上,框架中的派生类型确实做到了这一点。
看看它是如何实现的,它是相当复杂的。有一个从 Task 派生的自定义类(ReadWriteTask)负责异步读取。
ReadWriteTask
更多的是减少/合并分配,而不是“负责异步读取”。传递给该类的委托(在线程池线程上执行)是实际执行读取操作的委托。旁注:现代 .NET 运行时代码位于
here。
避免 DRY 的一种简单方法可能如下:[异步优于同步代码]它实际上与但是,在查看了他们的实现之后,我感觉上述方法可能是错误的/低效的。
Stream.ReadAsync
基本实现相同:将同步代码扔到线程池线程上。是的,您的代码和
Stream.ReadAsync
基本实现效率都很低。
你能建议一种模式来解决这个问题吗?我个人的偏好是
布尔参数 hack;更现代的版本是使用通用代码生成(正如我在博客中所描述的)。