C# 如何在不等待的情况下调用.NET中的异步函数
我在C#中有一个异步函数,如下所示:C# 如何在不等待的情况下调用.NET中的异步函数,c#,.net,async-await,C#,.net,Async Await,我在C#中有一个异步函数,如下所示: private static async Task AddEmoji(string emoji) { ... } 我有一种情况,我想打电话给它,但我不想等待它的结果,我不在乎它是否有效。正确的方法是什么?我想我可以在不添加async参数的情况下调用它: AddEmoji(“这不适用于asp.net--asp.net应用程序中不允许使用异步void方法。但是,控制台、WPF、Winforms等应用程序都可以。有关完整讨论,请参阅注释 最好的方法是在异步
private static async Task AddEmoji(string emoji)
{
...
}
我有一种情况,我想打电话给它,但我不想等待它的结果,我不在乎它是否有效。正确的方法是什么?我想我可以在不添加async参数的情况下调用它:
AddEmoji(“这不适用于asp.net--asp.net应用程序中不允许使用异步void
方法。但是,控制台、WPF、Winforms等应用程序都可以。有关完整讨论,请参阅注释
最好的方法是在异步void
方法中等待它
只写AddEmoji(“在你的Task.Run()中)的问题,wait不在Func中。你通常会在任务本身上等待(把wait
放在Task.Run()
之前),但我认为在你的情况下,你可以省略wait以避免等待并忽略结果:
Task.Run(()=>AddEmjoi(“
我不想等待它的结果,我也不在乎它是否有效
这是非常不寻常的;首先要检查的是这样一个假设,即你实际上不需要知道它何时完成(或是否完成),并且你可以默默地忽略所有异常。这也意味着,当你的应用程序退出时,你可以完成这项工作,永远不会完成(同样,你也不会知道,因为异常会被忽略)——记住,在ASP.NET这样的托管场景中,你无法控制你的应用程序何时退出
也就是说,你可以这样做“开火并忘记”:
var=AddEmoji(“你有没有试过在不等待的情况下调用它:Task.Run(()=>AddEmoji)(“这是第二次尝试-你可能需要Task.Run(async()=>await AddEmoji”)(“如果你不在乎它是否有效,为什么一开始就麻烦调用它?大家好-如果我调用@NikolaBabic或Marc的建议,我会得到一个CS4014(考虑应用“等待”操作员)警告。这并不是说我完全不在乎它是否有效——我只是不想等待它返回或知道它是否有效,因为如果它失败了,我不会特别采取不同的措施。请注意,在.NET 4.5之前将任务放到地板上是一个非常糟糕的主意。如果该任务包含异常,则该任务就是最终任务zer将重播它。这在4.5中被更改。“但它们非常适合于开火和遗忘的情况。”-不,我强烈反对-这是一件非常糟糕的事情,原因是:有框架(包括MVC)在其中被主动阻止-意思是:它会导致异常(由于同步上下文选择不允许)。我在语义上同意你的观点,但实际上:养成这样的习惯真的是一件非常糟糕的事情。如果它今天不咬你,它可能会因为内部框架的更改而在以后意外失败。我不得不重新发布库,因为我正是这样做的。@MarcGravel详细介绍了你所说的“主动阻止”的确切含义“请问?您的意思是捕获的SynchronizationContext不允许继续发布到它吗?这不是我遇到的问题-您是否有来源?当然,在“只需调用它并使用GC.KeepAlive
来抑制警告”中也存在同样的风险。”您在评论中提倡的方法,因为AddEmoji
可以在任何时候通过“主动阻止”发回同步上下文,我的意思是:当你这样做的时候,它实际上会抛出一个异常;同步上下文会这样做-在ASP.NET的情况下的错误是-这只发生在调用异步void
方法时-被引发(当\u state.AllowVoidAsyncOperations
为false
)当您使用任务调用GC.KeepAlive
时(将其放在地板上,同时让编译器高兴),它不会触发同步上下文显式查找的async void
场景(阻止)-因为它现在是一个异步任务
@marcGravel很有趣。完美,这正是我想要的。谢谢!这是我第一次看到反对异步void
的真正可靠的论据。我会更新我的答案。这需要一个新的线程池线程来运行AddEmoji
的第一位,这是不必要的昂贵如果我这样做,et a CS4014(考虑应用“wait”操作符)。它是有效的,但显然这不是最好的做法,因为我得到了警告。所以我想知道什么是“正确的”要做的事情。我也同意@ CangoN7——它看起来像使用任务。运行这里只是创建一个额外的层,我不使用。我经常碰到这种情况。考虑1)一种在无限循环中从流异步读取数据并发布其读取的帧的方法。此方法永远不会返回,但我希望我的应用程序在抛出意外异常时崩溃;2)执行异步操作并具有自己错误处理的System.Threading.Timer
回调;3)状态机的状态条目处理程序,它执行一些异步工作,并在工作成功或失败时在状态机上激发适当的事件。对于这些情况,我还没有找到比async void
更好的方法。@canton7:第一个示例不是“激发并忘记”,因为您希望检测错误。第二个示例是async void
的一个很好的用例-请注意,这是一个事件,这正是为什么async void
首先被添加到语言中的原因。第三个示例更可疑;在我看来,更好的设计可能是可能的,但即使有了这个示例,您也在谈论它g关于“处理程序”-即逻辑事件,即使它不是文字事件,因此async void
在那里也是可以接受的。感谢您的回复。很难找到解决这些情况的好方法,在fir中,“async void
之后永远不应该使用”