如果不等待任务呢?
本文关键字:任务 等待 如果不 | 更新日期: 2023-09-27 18:02:25
下面是我的代码:
private static Stopwatch _stopwatch;
static void PrintException(Exception ex)
{
Console.WriteLine(_stopwatch.Elapsed);
Console.WriteLine(ex);
}
static void ThrowException1()
{
throw new InvalidAsynchronousStateException();
}
static void ThrowException2()
{
throw new NullReferenceException();
}
static async Task ExecuteTask1()
{
await Task.Delay(1000);
ThrowException1();
}
static async Task ExecuteTask2()
{
await Task.Delay(2000);
ThrowException2();
}
static async Task Execute()
{
var t1 = ExecuteTask1();
var t2 = ExecuteTask2();
try
{
await t2;
}
catch (NullReferenceException ex)
{
// the NullReferenceException will be captured
Console.WriteLine("==============");
PrintException(ex);
}
}
static void Main(string[] args)
{
TaskScheduler.UnobservedTaskException += (sender, ev) => PrintException(ev.Exception);
_stopwatch = Stopwatch.StartNew();
Execute();
while (true)
{
Thread.Sleep(5000);
GC.Collect();
}
}
实际上,我没有在Execute
方法中等待t1
,但它似乎仍然被执行,因为我在大约五秒钟后捕获了AggregateException
。
谁能告诉我t1是什么时候执行的?在我的例子中,打印到控制台的异常顺序是1。NullReferenceException
2。AggregateException
在async/await世界中,任务是"hot"。因此,当您调用ExecuteTask1
时,返回给您的任务已经在处理中。它已经从那个点开始了。你可以把Console.WriteLine
放在ExecuteTask*
的开头,看看它们是否立即开始。
await
仅用于(异步)等待完成任务。它不启动任务。
我在我的博客上有一个async
的介绍,你可能会发现有帮助。
任务在您调用ExecuteTask1的点执行:
var t1 = ExecuteTask1();
你不需要等待任务执行,它会运行的…如果您希望您的代码仅在任务完成后才恢复执行,则可以等待任务,否则您的代码将在任务开始运行后立即继续运行,而不会等待它完成。
如果你没有await
一个任务,它仍然会执行,你当前的执行上下文将不会"等待它"。
这意味着你不能直接控制任务,如果"任务内部"出现问题,异常将不会像使用await
或t1.Wait()
时那样直接传播到你的执行上下文。
一般来说,在任务中抛出的异常被封装在AggregateException
中,所以你不能做以下操作:
catch (NullReferenceException ex)
你需要做这样的事情,例如检查内部异常:
catch (AggregateException ex)
{
if(ex.InnerException is NullReferenceException)
// handle NRE
else
throw; // NOT "throw ex" to keep the stack trace
}