C# 如果不等待任务怎么办?

C# 如果不等待任务怎么办?,c#,async-await,C#,Async Await,这是我的密码: private static Stopwatch _stopwatch; static void PrintException(Exception ex) { Console.WriteLine(_stopwatch.Elapsed); Console.WriteLine(ex); } static void ThrowException1() { throw new InvalidAsynchronousStateException(); } st

这是我的密码:

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
,但它似乎仍然被执行,因为大约五秒钟后我捕获了
aggregateeexception


有人能告诉我t1是什么时候执行的吗?在我的例子中,打印到控制台的异常顺序是1<代码>空引用异常2
aggregateeexception

如果您不等待它仍将执行的任务,那么您当前的执行上下文将不会“wati for it”

这意味着您无法直接控制任务,如果“任务内部”出现问题,异常将不会像使用
Wait
t1.Wait()时那样直接传播到您的执行上下文

在一般情况下,在任务中引发的异常被装箱在
聚合异常中
,因此不能执行以下操作:

catch (NullReferenceException ex)
您需要执行以下操作并检查内部异常:

catch (AggregateException ex)
{
    if(ex.InnerException is NullReferenceException)
        // handle NRE
    else
        throw; // NOT "throw ex" to keep the stack trace
}

该任务是在此处调用ExecuteTask1的点执行的:

var t1 = ExecuteTask1();

您不需要等待任务执行,它无论如何都会运行。。。如果希望代码仅在任务完成后恢复执行,则等待任务,否则代码将在任务开始运行后立即继续运行,而不等待任务完成。

在异步/等待世界中,任务是“热的”。因此,当您调用
ExecuteTask1
时,返回给您的任务已经在处理中。这一点已经开始了。您可以在
ExecuteTask*
的开头放置一个
Console.WriteLine
,以查看它们是否立即启动

wait
仅用于(异步)等待任务完成。它不会启动任务


我在我的博客上有一个你可能会觉得有用的工具。

注意:
NullReferenceException
是一个保留的异常,因此不应该从用户代码中抛出它。@SriramSakthivel+1,我只是出于演示的目的使用它。谢谢你的回复,但在我的情况下,如果我只是用
catch替换
catch(NullReferenceException ex)
(AggregateException ex)
,将不会捕获异常。您还可以捕获泛型
异常
,然后根据当前类型进行Deside…垃圾收集器是否也会跟踪此情况?假设您在类中执行此操作,则GC会因为认为没有更多引用而破坏属性吗?(如果您没有将任务返回/存储到任何位置)@JoelHarkes:在大多数情况下,任务不是GC'ed的,因为它们是由一个已传递给非托管代码的回调函数生成的。哈哈,谢谢“im most case”。好的,因此回调函数中使用的变量也不会被GC'ed。谢谢。@JoelHarkes:正确。
任务
在完成之前唯一可以被GC'ed的情况是ldn仍然没有完成。(假设每个人的非托管调用都正确地固定了他们所需的内存)。