【问题标题】:How to download correctly files simultaneously?如何同时正确下载文件?
【发布时间】:2019-11-29 20:44:00
【问题描述】:

我正在尝试同时下载多个文件。但是所有文件都在不断地下载。所以,首先这个文件下载@"http://download.geofabrik.de/europe/cyprus-latest.osm.pbf",然后这个文件开始下载@"http://download.geofabrik.de/europe/finland-latest.osm.pbf",,下一个要下载的文件是@"http://download.geofabrik.de/europe/great-britain-latest.osm.pbf"等等。

但我想同时下载

所以我有以下基于the code from this answer的代码:

static void Main(string[] args)
{
    Task.Run(async () =>
    {
        await DownloadFiles();
    }).GetAwaiter().GetResult();
}

public static async Task DownloadFiles()
{
    IList<string> urls = new List<string>
    {
        @"http://download.geofabrik.de/europe/cyprus-latest.osm.pbf",
        @"http://download.geofabrik.de/europe/finland-latest.osm.pbf",
        @"http://download.geofabrik.de/europe/great-britain-latest.osm.pbf",
        @"http://download.geofabrik.de/europe/belgium-latest.osm.pbf",
        @"http://download.geofabrik.de/europe/belgium-latest.osm.pbf"
    };

    foreach (var url in urls)
    {
        string fileName = url.Substring(url.LastIndexOf('/'));
        await DownloadFile(url, fileName);
    }            
}

public static async Task DownloadFile(string url, string fileName)
{
    string address = @"D:\Downloads";
    using (var client = new WebClient())
    {
        await client.DownloadFileTaskAsync(url, $"{address}{fileName}");
    }
}

但是,当我在我的文件系统中查看时,我看到文件正在逐个、逐个地下载,而不是同时下载:

另外,我尝试使用this approach,但是没有同时下载:

static void Main(string[] args)
{
    IList<string> urls = new List<string>
    {
        @"http://download.geofabrik.de/europe/cyprus-latest.osm.pbf",
        @"http://download.geofabrik.de/europe/finland-latest.osm.pbf",
        @"http://download.geofabrik.de/europe/great-britain-latest.osm.pbf",
        @"http://download.geofabrik.de/europe/belgium-latest.osm.pbf",
        @"http://download.geofabrik.de/europe/belgium-latest.osm.pbf"
    };

    Parallel.ForEach(urls,
        new ParallelOptions { MaxDegreeOfParallelism = 10 },
        DownloadFile);
}

public static void DownloadFile(string url)
{
    string address = @"D:\Downloads";
    using (var sr = new StreamReader(WebRequest.Create(url)
           .GetResponse().GetResponseStream()))
    using (var sw = new StreamWriter(address + url.Substring(url.LastIndexOf('/'))))
    {
        sw.Write(sr.ReadToEnd());
    }
}

你能告诉我如何同时下载吗?

任何帮助将不胜感激。

【问题讨论】:

  • 通过调用GetAwaiter().GetResult();,您正在同步运行您的代码。您使用的是哪个 .NET 版本? HttpClientasync Main() 呢?
  • @PavelAnikhouski 我正在使用 .NET 4.6。你能说明怎么可能吗?有没有更好的方法?
  • 尝试将Main定义为static async Task Main(string[] args) ,然后在里面调用`await DownloadFiles();`

标签: c# asynchronous async-await task-parallel-library parallel.foreach


【解决方案1】:
    foreach (var url in urls)
    {
        string fileName = url.Substring(url.LastIndexOf('/'));
        await DownloadFile(url, fileName); // you wait to download the item and then move the next
    }   

相反,您应该创建任务并等待所有任务完成。

public static Task DownloadFiles()
{
    IList<string> urls = new List<string>
    {
        @"http://download.geofabrik.de/europe/cyprus-latest.osm.pbf",
        @"http://download.geofabrik.de/europe/finland-latest.osm.pbf",
        @"http://download.geofabrik.de/europe/great-britain-latest.osm.pbf",
        @"http://download.geofabrik.de/europe/belgium-latest.osm.pbf",
        @"http://download.geofabrik.de/europe/belgium-latest.osm.pbf"
    };

       var tasks = urls.Select(url=> {
           var fileName = url.Substring(url.LastIndexOf('/'));
             return DownloadFile(url, fileName);    
         }).ToArray();   
         return Task.WhenAll(tasks);       
}

您的其余代码可以保持不变。

【讨论】:

  • 感谢您的回复!你能写出整个代码吗?我不明白我应该把这些代码放在哪里。
  • @Learner 查看我更完整的答案。 Eldar 的代码无法正常工作。
  • @user2966445 代码使用DownloadFiles函数已经等待函数。
  • @user2966445 你不能返回 Task.WhenAll(tasks) -> 当然可以。它返回一个Task,可以在调用堆栈中进一步等待。你是否真的想要那是另一回事。
  • @Eldar 我尝试输入您的代码,但是,我发现很多错误。
【解决方案2】:

Eldar 的解决方案在进行一些小的修改后即可使用。这是已编辑的完整工作 DownloadFiles 方法:

public static async Task DownloadFiles()
{
    IList<string> urls = new List<string>
{
    @"http://download.geofabrik.de/europe/cyprus-latest.osm.pbf",
    @"http://download.geofabrik.de/europe/finland-latest.osm.pbf",
    @"http://download.geofabrik.de/europe/great-britain-latest.osm.pbf",
    @"http://download.geofabrik.de/europe/belgium-latest.osm.pbf",
    @"http://download.geofabrik.de/europe/belgium-latest.osm.pbf"
};

    var tasks = urls.Select(t => {
        var fileName = t.Substring(t.LastIndexOf('/'));
        return DownloadFile(t, fileName);
    }).ToArray();   

    await Task.WhenAll(tasks);
}

【讨论】:

  • 谢谢你!有用!现在我不知道应该接受什么答案!非常感谢!
【解决方案3】:

这将一个接一个地异步下载它们。

await DownloadFile(url, fileName);
await DownloadFile(url2, fileName2);

这将完成您真正想要实现的目标:

var task1 = DownloadFile(url, fileName);
var task2 = DownloadFile(url2, fileName2);
await Task.WhenAll(task1, task2);

【讨论】:

  • 您应该删除第二个示例中的等待。
  • 感谢您的回复!但是,如果我有 100 个文件,那么我应该写 100 次这些行 var task1 = DownloadFile(url, fileName);
  • @Learner 不,你不应该。那只是为了描述它是如何“并行”完成的。您可以使用其他答案中所示的 for 循环。
猜你喜欢
  • 2011-05-26
  • 1970-01-01
  • 2018-11-17
  • 2021-05-05
  • 1970-01-01
  • 1970-01-01
  • 2023-03-05
  • 2017-04-27
相关资源
最近更新 更多