如果不等待任务呢?

本文关键字:任务 等待 如果不 | 更新日期: 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一个任务,它仍然会执行,你当前的执行上下文将不会"等待它"。

这意味着你不能直接控制任务,如果"任务内部"出现问题,异常将不会像使用awaitt1.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
}