foreach中的异步方法

时间:2018-01-09 14:59:14

标签: c# winforms asynchronous multitasking

我正在编写Windows窗体应用程序,我在从FTP服务器加载数据时遇到阻止UI的问题。

我有一份服务器列表,我可以从中获取信息。所以,当我点击按钮'从所有人那里获取'我从每个人那里得到信息。

private void GetInfoToolStripMenuItem_Click(object sender, EventArgs e)
{
    foreach (DataGridViewRow row in infoDataGridView.Rows)
        this.GetInfoAsync(row);
}

我从服务器获取信息时运行新任务以防止UI阻塞。方法 GetInfo 是异步的:

private async void GetInfoAsync(DataGridViewRow row)
{
    Server server = (Server)row.Cells[0].Value;
    row.Cells[1].Value = Resources.GettingIcon;

    await Task.Run(() =>
    {
        server.Data = dataGetter.GetData(server);
    });

    row.Cells[1].Value = Resources.FinishedIcon;
}

主要问题是:为什么foreach在 GetInfoAsync 完成之前开始新的迭代?我在此方法中使用 await 关键字,因此在数据完成之前执行不应该完成。

1 个答案:

答案 0 :(得分:4)

原因为什么你的循环将转移到下一个项目并再次调用GetInfoAsync,之前的完成是因为GetInfoAsync是火 - 和 - 忘记方法。

它被点燃了,因为它已被声明为async void并在内部开始一项新任务。

GetInfoAsync 等待这个子任务的事实并没有神奇地使GetInfoAsync方法等待,直到此子任务完成之前它会回来。

相反,这是发生的事情:

  1. 您的循环将在第一行调用GetInfoAsync
  2. GetInfoAsync会一直执行,直到它使用Task.Run生成子任务。
  3. 然后,使用await T的魔力在此子任务之后排队继续任务
  4. 然后它将返回循环
  5. 第一行的子任务完成后,将安排继续任务执行。

    您希望循环调用GetInfoAsync等待,然后再转到下一个需要使用循环更改方法的项目:

    1. 它也必须是async
    2. 需要await GetInfoAsync方法
    3. 因此GetInfoAsync也必须返回Task
    4. 这是你的最终代码:

      private async void GetInfoToolStripMenuItem_Click(object sender, EventArgs e)
      {
          foreach (DataGridViewRow row in infoDataGridView.Rows)
              await this.GetInfoAsync(row);
      }
      
      private async Task GetInfoAsync(DataGridViewRow row)
      {
          Server server = (Server)row.Cells[0].Value;
          row.Cells[1].Value = Resources.GettingIcon;
      
          await Task.Run(() =>
          {
              server.Data = dataGetter.GetData(server);
          });
      
          row.Cells[1].Value = Resources.FinishedIcon;
      }