3

我一直在阅读 .Net 4.5 中引入的 async/await 语法并有所了解。

我找到了简单的示例,其中 Task.Yield 是要走的路,而不是 Application.DoEvents。我尝试了其中一个样本(填空)

带有 1 个按钮的 Form1 上的代码:

public async void button1_Click(object sender, EventArgs e) {
    var list = new List<int>();
    for (int i = 0; i < 10000; i++) {
        list.Add(i);
    }
    for (int i = 0; i < list.Count; i++) {
        Process(list[i]);
        await Task.Yield();
        //await Task.Delay(1);
    }
}

public static void Process(int i) {
    Debug.WriteLine(i);
}

但是,运行此代码时,UI 线程被阻塞,或者我认为它被阻塞,因为在代码运行时我无法移动窗口。如果我注释掉 Task.Yield() 并改用 Task.Delay(1) 行,则 GUI 会响应。

那么我在这里误解了什么吗?我知道使用 DoEvents 等是不好的做法,但我有一些我负责的遗留代码使用它,我的目标是用 Yield 替换它,因为它是最佳选择。但首先我需要用 async/await 暖和起来。

4

1 回答 1

4

async不会神奇地使您的代码变好。Yield不是DoEvents(这是邪恶的)的直接替代品。更改代码的对齐方式需要一些工作。

只要您不需要 UI 上下文,您就可以将您的工作推送到线程池:

public async void button1_Click(object sender, EventArgs e) {
  await Task.Run(() => {
    var list = new List<int>();
    for (int i = 0; i < 10000; i++) {
      list.Add(i);
    }
    for (int i = 0; i < list.Count; i++) {
      Process(list[i]);
    }
  });
}

IProgress<T>或者,您可以考虑使用或Task.Run用于非 UI 工作来分解特定于 UI 的部分:

public async void button1_Click(object sender, EventArgs e) {
  var list = new List<int>();
  await Task.Run(() => {
    for (int i = 0; i < 10000; i++) {
      list.Add(i);
    }
  });

  for (int i = 0; i < list.Count; i++) {
    await ProcessAsync(list[i]);
  }
}

public static async Task ProcessAsync(int i) {
  await Task.Run(() => { ... }); // background
  myUi.Text = i.ToString() + " working"; // ui
  await Task.Run(() => { ... }); // more background
  myUi.Text = i.ToString() + " complete"; // ui
}
于 2012-10-29T15:13:15.203 回答