我正在实施IAsyncDisposable这要求我返回 a ValueTask,但有时我的 dispose 方法无关。在这种情况下我应该如何返回?
目前我正在返回new ValueTask(Task.CompletedTask)这似乎有效,但由于 valueTasks 的目的是避免创建不必要的堆对象,我相信应该有一种更简单、更有效的方法。
我有一个异步方法,看起来大约像这样:
async Task<int> ParseStream()
{
var a = await reader.ReadInt32();
var b = await reader.ReadInt32();
return a + b;
}
Run Code Online (Sandbox Code Playgroud)
由于数据已经准备好,因此该方法在大多数情况下都会同步工作。因此,用 ValueTask 替换返回类型以减少分配似乎是个好主意。但这会调用reader.ReadInt32()return Task。
所以问题是:从内部等待某些任务的方法返回 ValueTask 是否有意义?
这里提出的问题与这里的问题相同,旨在为其创建一个明确的解决方案。最准确的答案是 Stephen Toub 本人在本期中提出的,正是关于这个问题的。“推荐代码”如下:
public static ValueTask AsValueTask<T>(this ValueTask<T> valueTask)
{
if (valueTask.IsCompletedSuccessfully)
{
valueTask.GetResult();
return default;
}
return new ValueTask(valueTask.AsTask());
}
Run Code Online (Sandbox Code Playgroud)
这个答案不是最新的 - ValueTask 不公开 GetResult() (只有 Result 属性) - 问题是:
.GetAwaiter()上面缺少的调用吗?var fake = valueTask.Result;?总是?(我担心死代码消除。)public static ValueTask AsNonGenericValueTask<T>( in this ValueTask<T> valueTask )
{
return valueTask.IsCompletedSuccessfully ? default : new ValueTask( valueTask.AsTask() );
}
Run Code Online (Sandbox Code Playgroud) Task<T>我正在对和进行基准测试ValueTask<T>。源代码如下:
#LINQPad optimize+ // Enable compiler optimizations
void Main()
{
Util.AutoScrollResults = true;
BenchmarkRunner.Run<TaskAndValueTaskComparsion>();
}
[ShortRunJob]
public class TaskAndValueTaskComparsion
{
[Benchmark]
public ValueTask<int> RunValueTaskWithNew()
{
return new ValueTask<int>(1);
}
[Benchmark]
public Task<int> RunTaskFromResult()
{
return Task.FromResult(1);
}
}
Run Code Online (Sandbox Code Playgroud)
对于结果来说,Task<T>比 快得多ValueTask<T>。但为什么?我真的希望ValueTask<T>返回任务对象时会导致更少的分配。
我正在将异步委托传递给 LINQSelect方法,我更愿意获取ValueTasks列表而不是Tasks列表。我该怎么做?例子:
var result = (new[] { 0 }).Select(async x => await Task.Yield()).ToArray();
Console.WriteLine($"Result type: {result.GetType()}");
Run Code Online (Sandbox Code Playgroud)
结果类型:System.Threading.Tasks.Task[]
这是不可取的。我发现我可以通过用异步方法替换异步委托来创建我想要的列表,如下所示:
var result = (new[] { 0 }).Select(DoAsync).ToArray();
Console.WriteLine($"Result type: {result.GetType()}");
async ValueTask DoAsync(int arg)
{
await Task.Yield();
}
Run Code Online (Sandbox Code Playgroud)
结果类型:System.Threading.Tasks.ValueTask[]
这有效,但很尴尬。有什么办法可以保持简洁的委托语法,并且仍然得到ValueTask我想要的s 吗?
ValueTask并ValueTask<TResult>有一个Preserve()方法概括为“获取可以在将来任何时候使用的 ValueTask”。
这是什么意思以及我们什么时候应该使用它?这是否意味着ValueTask“在未来的任何时候”都不能使用“正常”?如果是这样,为什么?
如果 API 返回 aValueTask或ValueTask<T>,有没有办法对其执行 a ContinueWith,就像我可以做的那样Task?是否有 Microsoft 提供的 NuGet 库用于使用 .NET Standard 2.0 执行此操作?
我正在使用并发字典来存储数据来实现一个简单的查找服务。由于使用此服务的大多数方法都是异步的,因此我正在考虑使用ValueTask<TResult>.
伪代码:
public ValueTask<string> GetResultAsync(string key)
{
return ValueTask.FromResult(_dictionary.FirstOrDefault(p => p.Key == key).Value
}
Run Code Online (Sandbox Code Playgroud)
这种方法有意义吗?有什么注意事项吗?
有一个库返回 aValueTask并且我有一个消耗 ValueTask 的同步方法。问题是有以下警告:
CA2012:ValueTask 实例不应直接访问其结果,除非该实例已完成。与任务不同,在 ValueTask 上调用 Result 或 GetAwaiter().GetResult() 不能保证在操作完成之前阻塞。如果您不能简单地等待实例,请考虑首先检查其 IsCompleted 属性(或者如果您知道情况如此,则断言它是 true)。
我如何解决它?
public void CreateListenKey()
{
var result = CreateSpotListenKeyAsync().GetAwaiter().GetResult(); // CA2012: ValueTask instances should not have their result directly accessed unless the instance has already completed. Unlike Tasks, calling Result or GetAwaiter().GetResult() on a ValueTask is not guaranteed to block until the operation completes. If you can't simply await the instance, consider first checking its IsCompleted property (or asserting it's true if you …Run Code Online (Sandbox Code Playgroud)