Asynchronous downloading files in C#

2019-06-08 07:32发布

问题:

I have a question about asynchronous operations in C#. Suppose I have some code like this:

public async void Download(string[] urls)
{
    for(int i = 0; i < urls.Length; i++);
    {
        await DownloadHelper.DownloadAsync(urls[i], @"C:\" + i.ToString() + ".mp3");
    }
}

But this code does not really download files asynchronously. It begins to download the file from the first URL and then awaits this operation. It then begins to download the file from the second URL... and so on.

Thereby files are downloaded one by one, and I would like to get them started downloading simultaneously.

How could I do it?

回答1:

When you say asynchronous you mean concurrent, these are not the same. You can use Task.WhenAll to await for all asynchronous operations at the same time:

public async Task Download(string[] urls)
{
    var tasks = new List<Task>();
    for(int i = 0; i < urls.Length; i++);
    {
        tasks.Add(DownloadHelper.DownloadAsync(urls[i], @"C:\" + i.ToString() + ".mp3"));
    }

    await Task.WhenAll(tasks);
}

You should also refrain from using async void unless in an event handler



回答2:

Rather than awaiting individual tasks, create the tasks without waiting for them (stick them in a list), then await Task.WhenAll instead...

public async void Download(string[] urls)
{
    //you might want to raise the connection limit, 
    //in case these are all from a single host (defaults to 6 per host)
    foreach(var url in urls)
    {
        ServicePointManager
            .FindServicePoint(new Uri(url)).ConnectionLimit = 1000;
    }
    var tasks = urls
         .Select(url =>
             DownloadHelper.DownloadAsync(
                 url,
                 @"C:\" + i.ToString() + ".mp3"))
         .ToList();
    await Task.WhenAll(tasks);
}