使用 DownloadFileTaskAsync 一次下载所有文件

Dom*_*Dom 4 c# webclient task

给定一个包含 Urls 的输入文本文件,我想一次下载相应的文件。我使用这个问题UserState的答案 使用 WebClient 和 TaskAsync 从 Async CTP 下载作为参考。

public void Run()
{
    List<string> urls = File.ReadAllLines(@"c:/temp/Input/input.txt").ToList();

    int index = 0;
    Task[] tasks = new Task[urls.Count()];
    foreach (string url in urls)
    {
        WebClient wc = new WebClient();
        string path = string.Format("{0}image-{1}.jpg", @"c:/temp/Output/", index+1);
        Task downloadTask = wc.DownloadFileTaskAsync(new Uri(url), path);
        Task outputTask = downloadTask.ContinueWith(t => Output(path));
        tasks[index] = outputTask;
    }
    Console.WriteLine("Start now");
    Task.WhenAll(tasks);
    Console.WriteLine("Done");

}

public void Output(string path)
{
    Console.WriteLine(path);
}
Run Code Online (Sandbox Code Playgroud)

我预计文件的下载将在“Task.WhenAll(tasks)”点开始。但事实证明,输出看起来像

c:/temp/Output/image-2.jpg
c:/temp/Output/image-1.jpg
c:/temp/Output/image-4.jpg
c:/temp/Output/image-6.jpg
c:/temp/Output/image-3.jpg
[删除了许多行]
现在开始
c:/temp/Output/image-18.jpg
c:/temp/Output/image-19.jpg
c:/temp/Output/image-20.jpg
c:/temp/Output/image-21.jpg
c:/temp/Output/image-23.jpg
[删除了许多行]
完毕

为什么在调用 WaitAll 之前就开始下载?我可以改变什么来实现我想要的(即所有任务将同时开始)?

谢谢

Yuv*_*kov 5

为什么在调用 WaitAll 之前就开始下载?

首先,您不是在调用Task.WaitAll,它同步阻塞,而是调用Task.WhenAll,它返回一个应等待的可等待对象。

现在,正如其他人所说,当你调用一个异步方法时,即使没有使用await它,它也会触发异步操作,因为任何符合 TAP 的方法都会返回一个“热任务”。

我可以改变什么来实现我想要的(即所有任务将同时开始)?

现在,如果您想将执行推迟到Task.WhenAll,则可以使用Enumerable.Select将每个元素投影到 a Task,并在将其传递给 时将其具体化Task.WhenAll

public async Task RunAsync()
{
    IEnumerable<string> urls = File.ReadAllLines(@"c:/temp/Input/input.txt");

    var urlTasks = urls.Select((url, index) =>
    {
        WebClient wc = new WebClient();
        string path = string.Format("{0}image-{1}.jpg", @"c:/temp/Output/", index);

        var downloadTask = wc.DownloadFileTaskAsync(new Uri(url), path);
        Output(path);

        return downloadTask;
    });

    Console.WriteLine("Start now");
    await Task.WhenAll(urlTasks);
    Console.WriteLine("Done");
}
Run Code Online (Sandbox Code Playgroud)