【问题标题】:Upon await, when control goes to the caller, then does it process the next iteration of the for loop (Does await RETURN a task?)?在等待时,当控制权交给调用者时,它是否处理 for 循环的下一次迭代(是否等待返回任务?)?
【发布时间】:2021-10-31 18:26:36
【问题描述】:
private async void btnTest_Click(object sender, EventArgs e)
        {
            List<Task> lstTasks = new List<Task>();
            foreach (int val in lstItems)
            {
                lstTasks.Add(MyAsyncMtd(val));
            }
            await Task.WhenAll(lstTasks);
            ...
        }

        private async Task MyAsyncMtd(int val)
        {
            ...
            await Task.Delay(1000);
            ...
        }

问题:单击按钮时,在 for 循环的第一次迭代中,当遇到 MyAsyncMtd 中的 await 关键字时,我知道控制权转到了调用者。本例中的调用者是按钮单击方法。这是否意味着在第一次迭代的 Task.Delay 上等待 (Task.Delay) 时下一次迭代得到处理(换句话说 - 是否等待 return 任务给调用者?)?或者到底发生了什么?

【问题讨论】:

  • "这是否意味着在等待时会处理下一个迭代(Task.Delay)" -> 是的。
  • 从技术上讲,这是第一个可能创建延续的等待。但是,当您调用异步方法而不等待它时,它会启动任务热。因此,您一次创建了许多任务,然后等待它们。在这个楼层的制作过程中没有任何迭代受到伤害
  • 如果我这样做 lstTasks.Add(await MyAsyncMtd(val)); 会发生什么?
  • 同样的事情会降低装船的效率。你可以整天玩这个游戏,(这个和那个什么的以及其他什么)它并不能解决你的一般研究问题

标签: c# winforms asynchronous async-await


【解决方案1】:

下一次迭代发生没有任何等待 - 因为您还没有等待任务。因此,您将很快通过foreach 循环并到达Task.WhenAll。这将在所有任务完成后完成,即在最后一次 Task.Delay(1000) 调用执行后 1 秒。

await 运算符不会总是立即触发方法返回 - 它仅在操作数尚未完成时才会这样做。例如,考虑以下代码:

public async Task Method1()
{
    Console.WriteLine("1");
    Task task = Method2();
    Console.WriteLine("2");
    await task
    Console.WriteLine("3");
}

public async Task Method2()
{
    Console.WriteLine("a");
    await Task.FromResult(10);
    Console.WriteLine("b");
    await Task.Delay(1000);
    Console.WriteLine("c");
}

我希望输出是:

1 // Before anything else happens at all in Method1
a // Call to Method2, before the first await
b // The first await didn't need to return, because the FromResult task was complete
2 // Control returned to Method2 because the Delay task was incomplete
c // Awaiting the result of Method1 means the rest of Method1 executes
3 // All done now

【讨论】:

  • 像下面这样写是否会对我的代码运行方式产生任何影响:lstTasks.Add(await MyAsyncMtd(val));
  • @variable 这不会编译,因为await MyAsyncMtd(val); 不会返回任何给定示例代码的内容。即使它确实返回了一些东西,一旦将它作为await 的一部分解包,返回的东西也不是Task,所以无论如何你都无法将它添加到lstTasks(除非你的异步方法实际上是private async Task&lt;Task&gt; MyAsyncMtd(int val);).
  • 我想知道-既然 await 不返回任务,那么迭代如何继续将任务添加到列表中?
  • @variable:我不清楚你的意思,因为“因为等待不返回任务”有点不精确。 await 运算符的结果类型要么是空的,要么是正在等待的展开类型;如果可等待的表达式尚未完成,await 运算符使异步方法立即返回任务
  • @variable 我建议您以 Jon 的示例为基础来测试您的各种场景。
猜你喜欢
  • 1970-01-01
  • 2019-07-22
  • 1970-01-01
  • 2020-02-21
  • 1970-01-01
  • 2020-11-01
  • 2015-09-10
  • 2017-05-13
  • 1970-01-01
相关资源
最近更新 更多