当涉及到处理异步/任务时方法应该是什么样子时,我很困惑。
根据我的理解,一个只创建一个新任务的方法不需要是异步的,因为这会产生开销,因为它在新任务中包装了这个洞。
所以这个:
async Task _doStuff()
{
await Task.Run(()=> _stuff());
}
这样更好:
Task _doStuff()
{
return Task.Run(()=> _stuff());
}
然而,如果有一些前置条件检查,它会变得有点复杂 哪种方式更好呢?
async Task _doStuff()
{
if(stuffWasDone)
return;
await Task.Run(()=> _stuff());
}
或
Task _doStuff()
{
if(stuffWasDone)
return Task.Run(()=> {}); // this could be a static-readonly in some helper like AsyncHelper.Empty(); as there is no FromResult for Task.
return Task.Run(()=> _stuff());
}
答案 0 :(得分:4)
您不必使用Task.Run
来生成Task
。 Task
是一个承诺。
如果Task
不需要执行,请不要创建一个。使用Task.Run
有一个在线程池线程上调用空lambda的开销,你不需要它。简单回来就足够了。
如果实际上不需要Task.FromResult
,您也可以使用Task
:
Task DoStuffAsync()
{
if(stuffWasDone)
{
return Task.FromResult(0);
}
return Task.Run(() => _stuff());
}
如果您不想重新生成Task
,可以将其放在局部变量中:
private static Task _emptyTask = Task.FromResult(0);
至于你await
vs return await
的第一个例子,你不能说一个比另一个更“好”,因为它们用于不同的目的。前者将在返回之前异步等待Task
完成,而后者将向调用者返回热任务。这对于异常处理很重要。更重要的是,如果您之后不打算使用任务的结果,使用await
将导致冗余生成状态机。
另见旁注,wrapping synchronous methods in asynchronous wrappers is bad practice。让最终用户明确地调用Task.Run
,不要用异步行为欺骗他们。