C# 异步/等待-何时返回任务vs void?
在什么样的情况下你会想使用它C# 异步/等待-何时返回任务vs void?,c#,asynchronous,.net-4.5,C#,Asynchronous,.net 4.5,在什么样的情况下你会想使用它 public async Task AsyncMethod(int num) 而不是 public async void AsyncMethod(int num) 我能想到的唯一情况是,如果您需要任务来跟踪其进度 此外,在下面的方法中,是否不需要async和await关键字 public static async void AsyncMethod2(int num) { await Task.Factory.StartNew(() => Threa
public async Task AsyncMethod(int num)
而不是
public async void AsyncMethod(int num)
我能想到的唯一情况是,如果您需要任务来跟踪其进度
此外,在下面的方法中,是否不需要async和await关键字
public static async void AsyncMethod2(int num)
{
await Task.Factory.StartNew(() => Thread.Sleep(num));
}
任务
。主要的例外情况应该是当您需要一个void
返回类型(对于事件)时。如果没有理由不允许调用方等待您的任务,为什么不允许
void
的async
方法在另一个方面是特殊的:它们表示顶级异步操作,并具有在任务返回异常时起作用的附加规则。最简单的方法是通过一个示例来说明差异:
f
的异常总是“被观察到”。离开顶级异步方法的异常与任何其他未处理的异常一样简单处理g
的异常从未被观察到。当垃圾收集器来清理任务时,它看到任务导致了异常,并且没有人处理该异常。发生这种情况时,TaskScheduler.UnobservedTaskException
处理程序将运行。你不应该让这种事情发生。以你为例,
public static async void AsyncMethod2(int num)
{
await Task.Factory.StartNew(() => Thread.Sleep(num));
}
是的,在这里使用async
和wait
,它们可以确保在抛出异常时方法仍然正常工作
有关更多信息,请参阅:我遇到了这篇非常有用的文章,内容是关于Jérôme Laban撰写的
async
和void
:
底线是async+void
可能会使系统崩溃,通常只应在UI端事件处理程序上使用
这背后的原因是
AsyncVoidMethodBuilder,在本例中为无。当没有
环境同步上下文,未处理的任何异常
异步void方法的主体在线程池上重新引用。虽然
似乎没有其他合乎逻辑的地方可以解决这种问题
异常可能被抛出,不幸的结果是进程
正在终止,因为线程池上存在未处理的异常
从.NET 2.0起有效终止进程。你可以拦截
使用AppDomain.UnhandledException事件的所有未处理异常,
但无法从该事件中恢复进程
在编写UI事件处理程序时,异步void方法以某种方式
无痛,因为异常的处理方式与
非异步方法;他们被扔到调度员身上。有一个
从此类异常中恢复的可能性非常正确
在大多数情况下。但是,在UI事件处理程序之外,async void
方法使用起来有点危险,可能不那么容易找到
我认为您也可以使用
async void
启动后台操作,只要您小心捕获异常。想法
class Program {
static bool isFinished = false;
static void Main(string[] args) {
// Kick off the background operation and don't care about when it completes
BackgroundWork();
Console.WriteLine("Press enter when you're ready to stop the background operation.");
Console.ReadLine();
isFinished = true;
}
// Using async void to kickoff a background operation that nobody wants to be notified about when it completes.
static async void BackgroundWork() {
// It's important to catch exceptions so we don't crash the appliation.
try {
// This operation will end after ten interations or when the app closes. Whichever happens first.
for (var count = 1; count <= 10 && !isFinished; count++) {
await Task.Delay(1000);
Console.WriteLine($"{count} seconds of work elapsed.");
}
Console.WriteLine("Background operation came to an end.");
} catch (Exception x) {
Console.WriteLine("Caught exception:");
Console.WriteLine(x.ToString());
}
}
}
类程序{
静态bool isFinished=false;
静态void Main(字符串[]参数){
//启动后台操作,不关心它何时完成
背景();
WriteLine(“准备好停止后台操作时按enter键”);
Console.ReadLine();
isFinished=true;
}
//使用async void启动后台操作,该操作完成时没有人希望得到通知。
静态异步void BackgroundWork(){
//捕获异常非常重要,这样我们就不会使应用程序崩溃。
试一试{
//此操作将在十次迭代后或应用程序关闭时结束。以先发生的为准。
对于(var count=1;count调用async void的问题是
您甚至无法收回任务。您无法知道函数的任务何时完成。-
以下是调用异步函数的三种方法:
async Task somethingsync(){…return t;}
异步任务SomethingAsync(){…}
异步void SomethingAsync(){…}
在所有情况下,函数都被转换为一系列任务。不同之处在于函数返回的内容
在第一种情况下,函数返回一个最终生成t的任务
在第二种情况下,函数返回一个没有产品的任务,但您可以
仍在等待它知道它何时运行完成
第三种情况是令人讨厌的。第三种情况与第二种情况相似,除了
你甚至连任务都拿不回来你不知道什么时候
该函数的任务已完成
async void案例是一个“火灾和火灾”案例
忘记”:你启动了任务链,但你不在乎它何时启动
完成。当函数返回时,您只知道
直到第一次等待已经执行。第一次等待之后的一切
将在将来的某个未指定的点运行,而您没有
访问
我的答案很简单
你不能等待无效的方法
Error CS4008 Cannot await 'void' TestAsync e:\test\TestAsync\TestAsyncProgram.cs
因此,如果该方法是异步的,最好等待,因为您可能会失去异步优势。,永远不要使用async void
不要这样做:下面的示例使用async void
,它使
到达第一个等待时HTTP请求完成:
- 这在ASP.NET核心应用程序中始终是一种不好的做法
- 在HTTP请求完成后访问HttpResponse
- 使过程崩溃
我在评论中的意思是f
而不是g
。来自f
的异常被传递到SynchronizationContext
,g
将引发unobservedtaskeexception
,但是UTE
如果未处理,将不再使进程崩溃。在某些情况下,可以接受异常像这样的“异步异常”会被忽略
async Task<T> SomethingAsync() { ... return t; }
async Task SomethingAsync() { ... }
async void SomethingAsync() { ... }
Error CS4008 Cannot await 'void' TestAsync e:\test\TestAsync\TestAsyncProgram.cs