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
是一个类,这就是它可能减少分配的原因。( struct
s 大部分时间分配在堆栈上,因此当方法退出(退出 strackframe)时它们会自动消失。class
es 大部分分配在堆上,必须执行GC Collect或Sweep来收集无法访问的对象。因此,如果您可以在堆栈上分配,那么您的堆内存分配就不会增长(因为该对象),这就是不触发 GC 的原因。
ValueTask
当您的代码主要同步执行时,可以看到主要的好处。这意味着如果预期值已经存在,则无需创建承诺 ( TaskCompletionSource
),该承诺将在将来实现。
您也无需担心分配问题,Task<bool>
因为在这两种情况下,相应的任务对象都由运行时本身缓存。这同样适用于Task<int>
-1 到 9 之间的数字。参考
简而言之,Task
在这种情况下您应该使用而不是ValueTask
.
归档时间: |
|
查看次数: |
592 次 |
最近记录: |