从内部等待某些任务的方法到 return ValueTask 有什么意义

Is there any sense to return ValueTask from method that internally awaits some Tasks

我有一个异步方法,大致如下所示:

async Task<int> ParseStream()
{
    var a = await reader.ReadInt32();
    var b = await reader.ReadInt32();
    return a + b;
}

由于数据已经准备好,此方法大部分时间将同步运行。 因此,用 ValueTask 替换 return 类型以减少分配看起来是个好主意。 但这调用 reader.ReadInt32() return Task.

所以问题是:从内部等待某些任务的方法 return ValueTask 是否有意义?

是的,因为它是模式的一部分。你展示的是不阻塞异步模式的使用,所以如果你不在 return 中使用任务,它一定是阻塞的。

如果您不确定它是否适用于 ValueTask<T>,那可能是因为它不是。

Understanding the Whys, Whats, and Whens of ValueTask

您可以根据需要多次缓存和等待 Task<T>。它只有堆分配的缺点。

将方法的签名更改为 return a ValueTask 而不是 Task:

async ValueTask<int> ParseStreamAsync()
{
    var a = await reader.ReadInt32Async();
    var b = await reader.ReadInt32Async();
    return a + b;
}

... 的优点是调用您的方法的调用者将避免对象分配,以防对 reader.ReadInt32Async 的两个调用将同步完成。但这可能不是一个很大的优势,因为对 reader.ReadInt32Async 的两次调用可能仍会各自分配一个 Task 对象,具体取决于此方法的实现方式。理论上可能会缓存一些常见的 Task<Int32> return 值,但实际上可能性不大。如果 return 值为 Task<bool>,情况会有所不同,因为缓存仅有的两个可能值会很便宜。在引入 ValueTask 之前,缓存 Task<TResult> 对象是减少分配的唯一方法。

因此,通过使用 ValueTask 而不是 Task,您可以合理地期望每次调用时将对象分配从 3 减少到 2,这不是很令人印象深刻,但也不能忽略不计.