【问题标题】:.Net 4.5 and Task.Yield vs Task.Delay as an alternative to DoEvents? Which to use?.Net 4.5 和 Task.Yield vs Task.Delay 作为 DoEvents 的替代品?使用哪个?
【发布时间】:2012-10-18 21:43:09
【问题描述】:

我一直在阅读 .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 暖和起来。

【问题讨论】:

  • Task.Yield 的 MSDN 库文章中有明确说明:For this reason, do not rely on await Task.Yield(); to keep a UI responsive.
  • 好的。不良样本在网上发布,然后在其他博客上。
  • 这太奇怪了。据我所知,产量应该首先在 ui 事件循环中执行所有内容,然后在当前上下文中恢复。大开眼界。

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


【解决方案1】:

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&lt;T&gt;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
}

【讨论】:

  • 是的。我已经非常关注异步了,我用自己的异步库(.net 4.5 之前)来做这件事。但是我在阅读 async/await 时发现的示例只显示了带有 Task.Yield 的单击事件循环,据说它让给了 UI 线程。但是进行测试以获得它的感觉告诉我这实际上是行不通的。所以网上的样本要么是错误的,要么是我在那里的代码有问题。延迟有效。产量没有。
  • Yield 屈服于 UI 事件循环。但它首先安排自己的延续。所以由事件循环决定是先执行延续还是其他 UI 事件。例如,GetMessagedefines a priority for the messages it retrieves from the UI loop,可能无法与 Yield 配合使用。
  • 所以不能信任Yield 哟行为正确的方式来替换DoEvents。延迟仍然有效。但是Delay比DoEvents更好用吗?
  • 它仍然是一个 hack。你可以DoEvents留在里面;除了重构之外,没有任何好的替代品。
  • 对于 .Net 4.5,现在有一个 Dispatcher.Yield 静态方法,与 Task.Yield 不同
猜你喜欢
  • 2013-09-02
  • 2014-04-12
  • 2014-07-15
  • 2018-12-26
  • 2014-11-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多