将功能标记为异步但没有等待调用,有什么问题吗?

时间:2019-03-20 05:01:33

标签: c# async-await

具有标记为异步功能的功能是否有任何副作用,但实际上并没有进行任何等待调用?例如:

public interface IMyInterface
{
    Task DoSomethingAsync();
}

public class DoSomething1:IMyInterface
{
    public async Task DoSomethingAsync()
    {
        await getSomethingFromDatabaseAsync();
    }
}

public class DoSomething2:IMyInterface
{
    public async Task DoSomethingAsync()
    {
        doSomethingElse();
    }
}

IMyInterface由许多类实现,但是对于其中一个类,没有 await 调用。这会引起任何问题吗?

4 个答案:

答案 0 :(得分:7)

在具有返回任务的接口方法并且没有等待的情况下(是的,它发生了)。只需删除async关键字并返回Task.CompletedTask

Task.CompletedTask属性返回一个任务,该任务的Status属性设置为RanToCompletion

  

获取已成功完成的任务。

public class DoSomething2:IMyInterface
{
    public Task DoSomethingAsync()
    {
        doSomethingElse();
        return Task.CompletedTask;
    }
}

是的,有副作用,编译器正在检查IAsyncStateMachine并生成更多的 IL ,此外,将来的开发人员还将使用 ire 查看您的代码。至于其他功能上的区别,我想不到任何方便的地方。

答案 1 :(得分:2)

  

IMyInterface由许多类实现,但是对于其中一个类,没有等待调用。这会引起任何问题吗?

我要在这里进入危险地区,不同意埃里克·利珀特。在绝大多数情况下,在没有async的情况下使用await确实是一个错误,并且编译器警告很有用。我会说这在90%的时间都是正确的。

但是,我想说这种情况是该规则的例外。仅仅删除async / await的问题在于,异常的处理方式非常不同:

public Task DoSomethingAsync()
{
  // if doSomethingElse throws, that exception is raised directly;
  // it is *not* captured and placed on the returned task!
  doSomethingElse();
  return Task.CompletedTask;
}

Task返回方法的预期语义是捕获异常并将其放置在返回的Task上(至少,非bone-headed异常)。为了保留这些语义,您需要使用async(并禁止显示警告)或显式的try / catch

#pragma warning disable 1998
public async Task DoSomethingAsync()
#pragma warning restore 1998
{
  doSomethingElse();
}

// or

public Task DoSomethingAsync()
{
  try
  {
    doSomethingElse();
    return Task.CompletedTask;
  }
  catch (Exception ex)
  {
    return Task.FromException(ex);
  }
}

答案 2 :(得分:-2)

在您的情况下,我认为可能存在阻塞主线程的问题(这取决于您是否在乎),并且我认为这不是开发人员想要的。

如果没有任何等待调用,则可以执行以下操作,以免主线程被阻止(> .net 4.0):

create or replace trigger BIM
before insert on TABLE1 
 for each row
declare 
l_id_exists INT;
begin
    select CASE WHEN 
                 exists (select 1 from TABLE2 where TABLE2.ID = :new.ID) 
             THEN 1 
        ELSE 0 END INTO l_id_exists from dual;
   if l_id_exists = 0
   then
    raise_application_error(-20634, 'Error');
  end if;
end;
/

答案 3 :(得分:-3)

标记为异步的方法将以与只会产生一点开销的方式相同的方式工作,因为当将方法标记为异步时,编译器基本上会为该方法生成状态机。(在您的情况下,不会在某些特定方法中使用)< / p>

https://foreverframe.net/what-lies-beneath-asyncawait-in-c/

https://msdn.microsoft.com/en-us/magazine/jj991977.aspx