假设我有一个包含异步方法的接口,我有两个不同的接口实现。两种实现中的一种是自然异步,而另一种则不是。实现非异步方法的“最正确”方法是什么?
public interface ISomething {
Task<Foo> DoSomethingAsync();
}
// Normal async implementation
public class Implementation1 : ISomething {
async Task<Foo> ISomething.DoSomethingAsync() {
return await DoSomethingElseAsync();
}
}
// Non-async implementation
public class Implementation2 : ISomething {
// Should it be:
async Task<Foo> ISomething.DoSomethingAsync() {
return await Task.Run(() => DoSomethingElse());
}
// Or:
async Task<Foo> ISomething.DoSomethingAsync() {
return DoSomethingElse();
}
}
我试着跟上Stephen Cleary的blog,我知道其中任何一个都没有提供任何异步的好处,我对此很满意。第二个对我来说似乎更正确,因为它并没有假装它不是,但它确实给出了一个编译器警告,这些加起来并分散注意力。
如果这会产生影响,那么这一切都将在ASP.NET(包括Web MVC和WebAPI)中进行。
答案 0 :(得分:8)
您可以完全放弃async
修饰符并使用Task.FromResult
同步返回已完成的任务:
Task<Foo> ISomething.DoSomethingAsync()
{
return Task.FromResult(DoSomethingElse());
}
这会处理警告并具有更好的性能,因为它不需要async
方法的状态机开销。
然而,这有点change the semantics of exception handling。如果这是一个问题,那么您应该使用同步async
方法并接受警告(或通过注释将其关闭):
#pragma warning disable 1998
async Task<Foo> ISomething.DoSomethingAsync()
#pragma warning restore 1998
{
return DoSomethingElse();
}
正如Stephen Cleary建议您也可以通过等待已完成的任务来处理该警告(同时保持方法同步):
async Task<Foo> ISomething.DoSomethingAsync()
{
await Task.FromResult(false); // or Task.CompletedTask in .Net 4.6
return DoSomethingElse();
}
答案 1 :(得分:2)
这实际上取决于你的方法在做什么:
没有I / O,可忽略不计的cpu工作量
您应该同步计算结果并创建一个包含结果的任务。
Task<Foo> ISomething.DoSomethingAsync() {
Foo result;
// do something not hurting performance
// no I/O here
return Task.FromResult(result);
}
但请注意,调用方法时将抛出任何异常,而不是在等待任务时抛出异常。对于后一种情况,它符合其他类型的工作,你应该使用async:
async Task<Foo> ISomething.DoSomethingAsync() {
Foo result;
// do something not hurting performance
// no I/O here
return result;
}
cpu密集型工作
您应该使用Task.Run
启动任务,并在任务中执行cpu密集型工作。
Task<Foo> ISomething.DoSomethingAsync() {
return Task.Run(() => {
Foo result;
// do some CPU intensive work here
return result;
});
}
I / O密集型工作
您应该使用async
关键字并等待任何异步I / O方法。不要使用同步I / O方法。
async Task<Foo> ISomething.DoSomethingAsync() {
Stream s = new ....
// or any other async I/O operation
var data = await s.ReadToEndAsync();
return new Foo(data);
}