3

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

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

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

所以问题是:从内部等待某些任务的方法返回 ValueTask 有什么意义吗?

4

3 回答 3

4

更改方法的签名以返回 aValueTask而不是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>会缓存一些常见的返回值,但实际上可能性不大。如果返回值是Task<bool>,那将是不同的,缓存仅有的两个可能值会很便宜。在引入 s.cache 之前,缓存Task<TResult>对象是减少分配的唯一方法ValueTask

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

于 2020-01-28T16:01:28.070 回答
2

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

了解 ValueTask 的原因、内容和时间

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

于 2020-01-28T14:46:33.303 回答
0

是的,因为它是模式的一部分。您所展示的内容是不阻塞使用异步模式,因此如果您不使用任务作为回报,它必须是阻塞的。

于 2020-01-28T10:46:01.403 回答