与Implementing an interface that requires a Task return type in synchronous code类似,虽然我很好奇我是否应该忽略编译错误而不是我的情况。
假设我有这样的界面:
public interface IAmAwesome {
Task MakeAwesomeAsync();
}
在某些实现中,使用async
和await
异步完成可以带来很多好处。这正是界面试图允许的内容。
在其他情况下,也许很少见,只需要一个简单的同步方法即可实现。所以我们假设实现如下:
public class SimplyAwesome : IAmAwesome {
public async Task MakeAwesomeAsync() {
// Some really awesome stuff here...
}
}
这样可行,但编译器警告:
此方法缺少'await'运算符并将同步运行。 考虑使用
await
运算符等待非阻塞API调用, 或'等待TaskEx.Run(...)'在后台执行CPU绑定工作 线程。
编译器实际上是在建议这个解决方案:
public class SimplyAwesome : IAmAwesome {
public async Task MakeAwesomeAsync() {
await Task.Run(() => {
// Some really awesome stuff here, but on a BACKGROUND THREAD! WOW!
});
}
}
我的问题是 - 当我选择忽略此编译器警告时应该确定什么?在某些情况下,工作非常简单,为它产生一个线程无疑会适得其反。
答案 0 :(得分:11)
如果您确实想要同步进行工作,您知道您的async
方法将始终同步运行,并且在这种情况下是理想的,然后一定要忽略警告。如果您了解警告告诉您的内容并感觉它所描述的操作是正确的,那么这不是问题。这是一个警告而不是错误的原因。
当然,另一个选择是不要创建方法async
,而只是使用Task.FromResult
来返回已完成的任务。它会改变错误处理语义(除非你还捕获所有异常并将它们包装到你返回的任务中),所以至少要注意这一点。如果您确实希望在生成的Task
中传播异常,则可能值得保留方法async
并禁止警告。
答案 1 :(得分:6)
当我选择忽略此编译器警告时应该确定什么? 在某些情况下,工作非常简单,可以为它生成一个线程 无可否认会适得其反。
编译器并没有说“在此方法中使用Task.Run”。它只是告诉你,你准备了async
方法,将async
修饰符添加到方法声明中,但实际上并没有等待任何事情。
你可以采取三种方法:
一个。你可以忽略编译器警告,一切都会执行。请注意,状态机生成会有轻微的开销,但您的方法调用将同步执行。如果操作很耗时并且可能导致方法执行进行阻塞调用,则可能会使使用此方法的用户感到困惑。
B中。将“Awesome”的生成分为同步接口和异步接口:
public interface MakeAwesomeAsync
{
Task MakeAwesomeAsync();
}
public interface MakeAwesome
{
void MakeAwesome();
}
℃。如果操作不是太耗时,您可以使用Task
将其包裹在Task.FromResult
中。我肯定会在选择它之前测量运行CPU绑定操作所需的时间。
答案 2 :(得分:6)
正如其他人已经指出的那样,你有3种不同的选择,所以这是一个观点问题:
async
并忽略警告async
重载async
并返回已完成的任务。我建议您返回already completed task:
public class SimplyAwesome : IAmAwesome
{
public Task MakeAwesomeAsync()
{
// run synchronously
return TaskExtensions.CompletedTask;
}
}
有几个原因:
async
产生轻微的开销。await
的位置。async
时有些不和谐。这就像在代码中添加while(false){}
一样,它的行为相同,但它没有传达方法的含义。Servy指出,返回任务会改变异常处理的语义。虽然这是真的,但我认为这不是问题。
首先,大多数async
代码调用一个方法并在同一个地方等待返回的任务(即await MakeAwesomeAsync()
),这意味着无论方法是否都会在同一个地方抛出异常是async
或不是。
其次,甚至.Net框架的Task-returns方法也会同步抛出异常。以Task.Delay
throws an exception directly without storing it in the returned task为例,因此无需await
任务来提出异常:
try
{
Task.Delay(-2);
}
catch (Exception e)
{
Console.WriteLine(e);
}
由于.Net开发人员需要除了在.Net中同步遇到异常外,除了你的代码之外,它们也应该是合理的。