3

私は、.Net 4.5 で導入された async/await 構文を読んで、その感触を得てきました。

Application.DoEvents ではなく Task.Yield を使用する簡単なサンプルを見つけました。サンプルの 1 つを試してみました (空白を埋める)

ボタンが 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]);
    }
  });
}

または、非 UI 作業を使用するか、IProgress<T>または使用して、UI 固有の部分を分割することを検討できます。Task.Run

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 に答える