如果我不等待任务会怎样?
考虑这个例子:
var task = DoSomething() bool ready = await DoSomethingElse(); if (!ready) return null; var value = await DoThirdThing(); // depends on DoSomethingElse return value + await task;
DoSomething
做了一些可能需要一段时间的非常重要的工作,因此我们首先开始它。
与此同时,我们会检查我们是否已准备好使用DoSomethingElse
,如果没有,我们会提前退出。
我们只有在ready
才会调用DoThirdThing
,因为宇宙可能会爆炸。
我们不能使用Task.WhenAll
因为DoThirdThing
依赖于DoSomethingElse
,我们也不想等待DoSomething
因为我们想要尽可能同时调用其他两个方法。
问题是:如果我们还没有ready
并提前退出,会发生什么?
它会抛出的任何exception会被SynchronizationContext
重新抛出吗?
如果task
正常完成,是否存在问题,因为没有人消耗它的价值?
后续行动:有没有一种巧妙的方法来确保等待task
?
如果我们还没ready
,我们可以简单地await task
,但是如果有50个退出条件,那将非常繁琐。
是否可以使用finally
块来await task
并重新抛出潜在的exception? 如果task
正常完成,则会在finally
块中再次等待,但这不会导致任何问题吗?
问题是:如果我们还没有准备好并提前退出,会发生什么?
没有。 代码忽略任务,因此忽略该任务。
它会抛出的任何exception会被SynchronizationContext重新抛出吗?
不会。他们将(最终)传递给TaskScheduler.UnobservedTaskException
然后被忽略。
如果任务正常完成,是否存在问题,因为没有人消耗它的价值?
不。
后续行动:有没有一种巧妙的方法来确保等待任务?
没有。
是否可以使用finally块来等待任务并重新抛出潜在的exception?
是的,如果您的代码实际await
任务。 据推测,这意味着在某处保存任务。
如果任务正常完成,则会在finally块中再次等待,但这不会导致任何问题吗?
您可以根据需要多次await
任务。
如果我们还没准备好,我们可以简单地等待任务,但是如果有50个退出条件,那将非常繁琐。
然后考虑重组您的代码。
后续行动:有没有一种巧妙的方法来确保等待任务?
如果您需要单独的,比TaskScheduler.UnobservedTaskException
更细粒度地控制您不await
的任务抛出的exception,那么有一个方便的工具: async void
方法。
您的代码可能如下所示:
static async void Observe(Task task) { // use try/catch here if desired so; // otherwise, exceptions will be thrown out-of-band, ie // via SyncronizationContext.Post or // via ThreadPool.QueueUSerWorkItem (if there's no sync. context) await task; } // ... var taskObserved = false; var task = DoSomething() try { bool ready = await DoSomethingElse(); if (!ready) return null; var value = await DoThirdThing(); // depends on DoSomethingElse taskObserved = true; return value + await task; } finally { if (!taskObserved) Observe(task); }
在这里和这里可以找到更多细节。