simple-thomas
simple-thomas

Reputation: 729

How can I create call an async method inside another async method without it stalling

I need to call multiple async methods and inside of them, call another async method aswell. Let me demonstrate

private async void button1_Click(object sender, EventArgs e)
{
    for(int i = 0; i< 100; i++)
    {
        await Method1();
    }
}

public async Task Method1()
{
    await Task.Delay(3*1000);
    await Method2();
}

public async Task Method2()
{
    await Task.Delay(10*1000);
}

My problem is, the for statement only activates the iterations after the wait on Method2 starts and what I want is to create the 100 Task all at once. Everything else will be done asynchronously.

Upvotes: 5

Views: 10954

Answers (2)

Eric Lippert
Eric Lippert

Reputation: 660038

I think you are confused as to what "await" means. "await" means "start processing this thing asynchronously, and while that is ticking away, go back to the windows message loop and keep on processing messages so that the UI keeps on re-drawing. When the asynchronous task is done, pick up the code where I awaited".

So when you await in a loop like that, you are saying:

  • Start the first asynchronous job...
  • and while it is running, keep processing the message loop.
  • When the first asynchronous job is done...
  • pick up in the loop where we awaited. We go around the loop and...
  • Start the second asynchronous job...

If that's not what you want then don't await the task. If you want to start a hundred tasks that run concurrently then start a hundred tasks and don't await any of them. Why is there any await in the click handler?

Upvotes: 9

Servy
Servy

Reputation: 203820

Rather than await-ing each tasks as you create it in the for loop, you just want to start all of the tasks. You don't want to delay the scheduling of the next task until the previous finished, so just don't await:

private void button1_Click(object sender, EventArgs e)
{
    for(int i = 0; i< 100; i++)
    {
        var task = Method1();
    }
}

Done.

If it's important that you do something after all of the tasks finish, while still doing all of them in parallel, then you can rely on Task.WhenAll to generate a task that will be completed when all of the other tasks are done:

private async void button1_Click(object sender, EventArgs e)
{
    var tasks = new List<Task>();
    for(int i = 0; i< 100; i++)
    {
        tasks.Add(Method1());
    }
    await Task.WhenAll(tasks);
    textbox1.Text = "Done!"; //or whatever you want to do when they're all done
}

Upvotes: 3

Related Questions