问题 如何正确实现TAP方法?


我想提供一个基于任务的异步模式样式方法。在等待该方法时,我发现这两种提供方法的方法之间没有任何区别:

// GetStats is a delegate for a void method in this example
public Task GetStatsAsync()
{
    return Task.Run(GetStats);
}

public async Task GetStatsAsync()
{
    return await Task.Run(GetStats);
}

// Usage:
await GetStatsAsync();
// Difference?

上层方法似乎比下层方法具有更少的开销。在查看MSDN博客时,我注意到他们似乎使用较低的方法。 (例如在 本文

为什么?究竟有什么区别?他们似乎都工作。


6399
2017-08-14 12:18


起源

您可能想要编辑您的问题并替换 TaskEx 同 Task因为这是现在众所周知的方式。 - Varvara Kalinina
@Varvara Kalinina完成 - nikeee


答案:


这些在逻辑上是相同的,但第二个有更多的开销,因此不推荐。

你可能会找到我的 async 介绍很有帮助,以及 基于任务的异步模式文档

有关开销的更多信息 async,我推荐 Stephen Toub的Async之禅

你可能也想读 “我应该为同步方法公开异步包装吗?” 简而言之,答案是“不”。


10
2017-08-14 12:37



第一个也不推荐!让调用者选择是否要在线程池上运行。只是将Task.Run放在那里并不会使算法神奇地无阻塞。 - usr
看到我更新的答案。 - Stephen Cleary
他们确实使用第一个样本中的Run方法进行进度报告(int processCount = await Task.Run<int>(() =>)。 - nikeee
你是对的。 MSDN示例代码效率不高。 - Stephen Cleary


我的印象是,实施TAP模式的正确方法如下:

  public Task<IResult> GetLongWindedTaskResult(){
          var tcs = new TaskCompletionSource<IResult>();
            try
            {
               tcs.SetResult(ResultOFSomeFunction());
            }
            catch (Exception exp)
            {
                tcs.SetException(exp);
            }
            return tcs.Task;
}

这种方式可确保您在抛出时正确获取异常,并且如果需要,可以更轻松地实现cancel方法。


3
2017-08-17 18:45