这是我在重构一些遗留代码时遇到的问题。
考虑一个返回Task
的接口的方法:
public interface IFoo
{
Task Bar();
}
Bar
方法实现可以通过两种方式实现:
返回Task
:
public class Foo1 : IFoo
{
public Task Bar()
{
return Task.Run(() =>
{
/* some work */
});
}
}
或使用async
... await
:
public class Foo2 : IFoo
{
public async Task Bar()
{
await Task.Run(() =>
{
/* some work */
});
}
}
这些实现在功能上是等同的,还是存在(可能是微妙的)差异?
答案 0 :(得分:2)
由于使用async-await语法会导致编译器生成在任务完成后实际继续通过await语句的代码,因此存在很大差异。此外,等待出现故障的任务会导致异常冒泡,这意味着它不再被视为未被观察到......我认为还有更多,我真的建议你看看Jon Skeet&#39 ; s C#5在复数视频上的异步课程,他实际上是通过编译器生成的代码并解释它。
答案 1 :(得分:1)
返回任务
Foo1.Bar
只是一个常规的同步方法,它返回一些对象实例(特别是Task
)。
或使用async ...等待
Foo2.Bar
是异步方法,它将被编译到状态机中。这里会有一些开销。
请注意,未来版本的Roslyn will convert方法会像这样进入同步方法。
但实际上,你不应该在这里使用Task.Run
。有关详细信息,请参阅此post。
答案 2 :(得分:0)
第二个实现返回一个封装另一个等待任务的任务。这将产生不需要的代码膨胀,内存使用和可能的另一个线程创建,只是为了实现与第一个相同的目标。