传递给 Task.WaitAll() 的任务会在不同的上下文上运行吗?



让我们假设我有以下代码:

await Task1Async().ConfigureAwait(false);
await Task2ASync().ConfigureAwait(false);

配置 await 允许在与调用线程不同的线程上运行。

但是如果我执行以下操作:

Task.WaitAll(
Task1Async,
Task2Async
);
  • 任务是否在同一上下文中运行?
  • 如果没有,我可以做一个等效的配置等待(假(吗?
async Task TestAsync()
{
await Task1Async().ConfigureAwait(false);
await Task2ASync().ConfigureAwait(false);
}

配置 await 允许在与调用线程不同的线程上运行。

澄清一下,代码示例中的ConfigureAwait(false)Task1AsyncTask2Async中的代码绝对没有影响。默认情况下,await将捕获其上下文并在该上下文上恢复;这适用于await所在的方法 -TestAsync上面的代码。有关详细信息,请参阅我的异步介绍。

但是,如果我[使用Task.WaitAll],任务是否在同一上下文中运行?

Task.WaitAll用于等待任务。它不运行任务。TAP 模式指定任务返回"热",即已在进行中。因此,当您的代码调用Task1Async()并取回任务时,该任务已在进行中。代码获取任务后,告诉它在哪里运行为时已晚 - 它已经开始了。

如果没有,我可以做一个等效的配置等待(假(吗?

如果你的意思是,"我可以在后台线程上运行这段代码吗?",那么你可以使用Task.Run

// Start Task1Async on a background thread.
var task1 = Task.Run(() => Task1Async());
// Start Task2Async on a background thread.
var task2 = Task.Run(() => Task2Async());
// Asynchronously wait for both tasks to complete.
await Task.WhenAll(task1, task2);

据我了解的一些解释。

如果您这样做:

//some code
await Task1Async();
await Task2ASync();
//some other code

它将像这样执行:

  1. 调用线程(例如 UI 上下文(同步执行"某些代码"。
  2. 然后,它异步启动 Task1Async,这将发生在 ThreadPool 上下文中(除非它已经完成,在这种情况下,执行在下面的第 4 点同步继续(。 如果任务未完成,则在此处捕获调用上下文
  3. 然后,当前线程从函数返回,这意味着它不会被阻塞。
  4. 当 Task1Async 完成后,下一行将在捕获的上下文中执行,例如 UI 上下文。 然后,这将通过线程池上下文异步启动 Task2Async(如果已完成,则继续同步执行(
  5. Task2Async 完成,然后最后使用捕获的上下文再次运行"其他代码">

如果您改为这样做:

//some code
await Task1Async().ConfigureAwait(false);
await Task2ASync().ConfigureAwait(false);
//some other code

这是发生的情况:
1.调用线程执行"一些代码"。
2. 然后异步执行 Task1Async(线程池(。
3. 当前线程从函数返回,这意味着它没有被阻塞。 4. 当 Task1Async 完成时,下一行不是在捕获的上下文上执行,而是使用线程池执行。 然后启动 Task2Async。 5. Task2Async 完成,然后再次运行最终的"其他代码",而不是在调用线程上,而是使用线程池。

在这两种情况下,函数都按顺序运行,但不会阻塞调用线程。

使用 Task.WaitAll,这两个任务使用线程池按顺序运行。 即每个任务在单独的线程中启动并等待完成。 这里的主要区别在于调用线程被阻塞,直到两个任务都完成。

如果要并行运行这两个任务并且不阻止调用线程,则可以等待 WhenAll:

await Task.WhenAll(Task1Async, Task2Async);

最后,如果您在 await 之后有任何想要运行的代码不需要在 UI 上下文中运行,那么您可以执行以下操作:

await Task.WhenAll(Task1Async, Task2Async).ConfigureAwait(false);

旁注:您想要 ConfigureAwait(true( 或省略它的原因是,如果您有一个按钮单击处理程序并希望更新需要在 UI 线程上的内容:

public void OnClick(..args..)
{
Button.IsEnabled = false;
await SomeTask();
//must be on UI thread. This code is executed on the context captured by the await above.
Button.IsEnabled = true;
}

最新更新