非异步方法中使用Task.ContinueWith与使用async/await的性能比较

6
假设你有一个方法,它包装了一个内部长时间运行的方法。这个外部方法在调用该长时间运行的方法之前/之后可能会执行少量的工作。例如:
public async Task<int> LongRunningWrapperAsync()
{
    int result = await LongRunningAsync();
    result++;
    return result;
}

看起来使用async生成的样板代码增加的重量并不一定值得使用await的好处,因为它的续体基本上是琐碎的。因此,如果给定一个足够琐碎的续体,使用Task.ContinueWith更具性能优势吗?例如:

public Task<int> LongRunningWrapperAsync()
{
    return LongRunningAsync().ContinueWith(task => task.Result + 1,
                 TaskContinuationOptions.ExecuteSynchronously);
}
< p >< em > * 是的,“足够”和“琐碎”这两个词都含糊不清。此外,在这个刻意制造的示例中,我忽略了异常处理。我想需要处理异常意味着继续是非琐碎的。

1
只需自己尝试一下-使用System.Diagnostics.Stopwatch并执行每个代码大量次数。 - Knaģis
2
我不同意你的例子是“琐碎”的说法。async/await 会将异常情况和正常情况都连接到你的后续操作中,这使得开发更加容易。使用库和框架的重点通常在于处理一个琐碎概念周围的边缘情况。 - Aron
1个回答

10
因此,如果给定一个足够简单的 continuation,使用 Task.ContinueWith 的性能更优吗?
是的,但我认为这是错误的问题。
虽然性能更好,但您必须非常小心地处理边缘情况(特别是,LongRunningAsync 引发的任何异常都将被包装在代码中的 AggregateException 中)。另外,await 默认会捕获上下文,并在该上下文中恢复方法。通过 ContinueWith 可以更有效地处理特殊情况,但无法更有效地处理通用情况。
但是,无论如何,性能都是错误的问题。我认为更好的问题是:“代码是否已足够高效,并且如果是,哪种解决方案更易于维护?”
考虑代码将被执行的次数。数百万次?可以节省多少时间?几个纳秒?使用 ContinuWith 方法的开发人员需要花费多少时间?每当有人查看代码时,理解代码所需的时间就会变长。使代码更易于维护(将节省的时间集中在公司内)比在运行代码时节省绝对微小的时间更明智。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接