首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如果我仍然使用ValueTask来实现异步,我应该返回TaskCompletionSource吗?

如果我仍然使用ValueTask来实现异步,我应该返回TaskCompletionSource吗?
EN

Stack Overflow用户
提问于 2020-07-08 06:04:51
回答 2查看 1.3K关注 0票数 5

如果我使用ValueTask实现实际的异步,返回TaskCompletionSource还有好处吗?

据我所知,ValueTask的目的是减少分配,但在等待TaskCompletionSource.Task时,分配仍然存在。下面是一个简单的例子来说明这个问题:

代码语言:javascript
复制
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();
    }
}

我是否应该从Task (相对于ValueTask)返回DispatcherTimerDelayAsync,它本身总是被期望是异步的?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-07-08 06:26:27

每种方法各有优缺点。在“专业”一栏中:

  1. 当同步返回结果(即Task<T>)时,使用ValueTask<T>可以避免任务的分配--但是,这个不会将应用于"void“(即非泛型Task),因为您可以只返回Task.CompletedTask
  2. 当您发出多个顺序的awaitables时,可以使用带有顺序令牌的单个“值任务源”来减少分配。

( "2“的特例可能是通过像PooledAwait这样的工具摊销)

这两种方法都不适用于此,但是:如果有疑问,请记住,将Task作为ValueTask (return new ValueTask(task);)返回是免费的,这将允许您考虑稍后将实现更改为无分配的实现,而不会破坏签名。当然,您仍然需要支付原始Task等的费用--但将它们作为ValueTask公开并不会增加任何额外费用。

老实说,在这种情况下,我不确定我是否会担心太多,因为拖延是分配的方式。

票数 8
EN

Stack Overflow用户

发布于 2020-07-08 06:13:34

ValueTask是一个结构,而Task是一个类,这就是它可能减少分配的原因。(struct大部分时间都在堆栈上分配,所以当方法退出时,它们会自动消失(退出strackframe)。classes主要在堆上分配,在堆中必须执行GC 收集扫描来收集不可访问的对象。因此,如果可以在堆栈上分配,那么堆内存分配就不会增加(因为这个对象),这就是GC没有被触发的原因。

当您的代码主要同步执行时,可以看到ValueTask的主要好处。这意味着,如果期望值已经存在,那么就没有必要创建一个承诺(TaskCompletionSource),它将在未来实现。

您也不需要担心在Task<bool>情况下的分配,因为在这两种情况下,相应的任务对象都是由运行时本身缓存的。同样的情况也适用于Task<int>,但仅适用于-1到9之间的数字。

因此,总之,在这种情况下,您应该使用Task而不是ValueTask

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62788515

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档