Question

I have been reading up on the async/await syntax introduced in .Net 4.5 and getting a feel of it.

I have found simple samples where Task.Yield is the way to go rather than Application.DoEvents. I tried one of the samples (filling in the blanks)

Code on Form1 with 1 button:

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);
}

However, running this code, the UI thread is blocked or I believe it is blocked as I can not move the window while the code runs. If I comment out the Task.Yield() and use the Task.Delay(1) line instead, the GUI is responsive.

So have I misunderstood something here? I know using DoEvents and the like is bad practice, but I have some legacy code I am responsible for that uses this, and I aim to replace it with Yield as it is the best choice. But first I need to get warm with async/await.

Was it helpful?

Solution

async doesn't magically make your code good. Yield is not a direct replacement for DoEvents (which is evil). It will take some work to change the alignment of your code.

As long as you don't need the UI context, you can just push your work off to the threadpool:

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]);
    }
  });
}

Alternatively, you can consider breaking up the UI-specific parts either using IProgress<T> or using Task.Run for the non-UI work:

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
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top