avo*_*avo 4 .net c# async-await .net-core
ValueTask如果我TaskCompletionSource用来实现实际的异步,返回还有好处吗?
据我了解, 的目的ValueTask是减少分配,但在 await 时分配仍然存在TaskCompletionSource.Task。这是一个简单的例子来说明这个问题。我应该从 返回Task(而不是ValueTask)DispatcherTimerDelayAsync,它本身总是被期望是异步的?
async ValueTask DispatcherTimerDelayAsync(TimeSpan delay)
{
var tcs = new TaskCompletionSource<bool>();
var timer = new DispatcherTimer();
timer.Interval = delay;
timer.Tick += (s, e) => tcs.SetResult(true);
timer.Start();
try
{
await tcs.Task;
}
finally
{
timer.Stop();
}
}
Run Code Online (Sandbox Code Playgroud)
各有利弊。在“亲”栏中:
Task<T>)时,使用ValueTask<T>避免了任务的分配 - 但是,这不适用于“void”(即非泛型Task),因为您可以只返回Task.CompletedTask(“2”的特殊情况可能是通过诸如 之类的工具进行摊销PooledAwait)
它不觉得像这类原因适用于这里,但是:如有疑问,请记住,这是分配,自由地返回Task 作为一个ValueTask(return new ValueTask(task);没有更高版本),这将让你考虑改变实施的无偿划拨一破坏签名。当然,您仍然需要为原始Task等付费- 但将它们暴露为ValueTask不会增加任何额外费用。
老实说,我不确定在这种情况下我是否会为此担心太多,因为延迟是一种分配方式。
ValueTask是一个结构,而Task是一个类,这就是它可能减少分配的原因。( structs 大部分时间分配在堆栈上,因此当方法退出(退出 strackframe)时它们会自动消失。classes 大部分分配在堆上,必须执行GC Collect或Sweep来收集无法访问的对象。因此,如果您可以在堆栈上分配,那么您的堆内存分配就不会增长(因为该对象),这就是不触发 GC 的原因。
ValueTask当您的代码主要同步执行时,可以看到主要的好处。这意味着如果预期值已经存在,则无需创建承诺 ( TaskCompletionSource),该承诺将在将来实现。
您也无需担心分配问题,Task<bool>因为在这两种情况下,相应的任务对象都由运行时本身缓存。这同样适用于Task<int>-1 到 9 之间的数字。参考
简而言之,Task在这种情况下您应该使用而不是ValueTask.
| 归档时间: |
|
| 查看次数: |
592 次 |
| 最近记录: |