.Net 4.5和Task.Yield vs Task.Delay作为DoEvents的替代品?哪个用?

时间:2012-10-29 14:48:19

标签: delay .net-4.5 yield doevents async-await

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

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

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

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获得热情。

1 个答案:

答案 0 :(得分: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
}