2

Imagine I have an async function that takes data from an url and outputs it to a file, and an async function that calls the first function for a list of urls, like this:

static async Task UrlToFileAsync(Uri url, string filePath)
{
    //...
}

public static async Task GetDataAsync(List<Uri> urlList, string filePath)
{
    foreach (Uri url in urlList)
    {
        await UrlToFileAsync(url, filePath);
    }
}

My question is, will the Task from GetDataAsync only be considered completed when the Task for each url called in the loop is completed? Does the program creates an array or list of Tasks somewhere to monitor the state of each call of UrlToFileAsync?

Janilson
  • 1,042
  • 1
  • 9
  • 23
  • 2
    The task is completed when `async GetDataAsync` completes, e.g., when the end of the method is reached, or a `return` statement is hit. That is the case for _all_ `async` methods. The method may suspend and resume many times before it finishes, but the returned task will not complete until the `async` body 'exits'. Since each task in your loop is awaited, all of those tasks are guaranteed to have completed before you reach the end of `GetDataAsync`, at which time the method (asynchronously) exits. – Mike Strobel Apr 04 '18 at 14:00

1 Answers1

4

Will the Task from GetDataAsync only be considered completed when the Task for each url called in the loop is completed?

Yes, that's correct.

Does the program creates an array or list of Tasks somewhere to monitor the state of each call of UrlToFileAsync?

You're awaiting UrlToFileAsync(), so when the method completes, execution will be returned to GetDataAsync(). async/await basically lets your application release the thread its using back to the thread pool when it does I/O work, and once the I/O work is complete, it will resume the CPU-bound execution and eventually return to the context of the calling method. There's a much more detailed explanation of that here. You can also find more information on Stephen Cleary's blog.

At the moment, you're running each url sequentially, so you're not using the full benefit of asyinc/await. If you want to parallelize the tasks, you should do something like this:

public static async Task GetDataAsync(List<Uri> urlList, string filePath)
{
    // create an array of tasks
    var tasks = urlList.Select(u => UrlToFileAsync(u, filePath)).ToArray();
    // wait for them all to complete
    await Task.WhenAll(tasks);
}
ProgrammingLlama
  • 36,677
  • 7
  • 67
  • 86
  • A second soubt ended up occurring to me today. I'm outputting all the data to the same file, so If I parallelize the tasks like you suggest how would the program know the order in which the data is supposed to be written? After all there's a chance the second Url called might respond faster than the first one for example – Janilson Apr 05 '18 at 16:21
  • I'm afraid I have to sleep now. I'll reply sometime tomorrow. – ProgrammingLlama Apr 05 '18 at 16:30