快速下载1,000多个文件?

时间:2018-04-23 02:00:15

标签: c# .net

我目前有一个链接到图片或MP4文件的网址列表,重新编码运行速度更快的最佳方法是什么?我知道我可以运行多个线程甚至是并行但最好的方式是什么?我不要太担心速度,只要它不像现在这么慢,但我不想过度使用设备的资源,例如CPU试图加快速度

sock

3 个答案:

答案 0 :(得分:2)

更新

Jimi 在评论中向我指出,DownloadFileAsync是一个事件驱动的电话而不是等待。但是,有一个WebClient.DownloadFileTaskAsync版本,在此示例中使用的是适当的版本,它是一个等待的调用并返回Task

  

将指定资源作为异步下载到本地文件   使用任务对象进行操作。

原始答案

  

我知道我可以运行多个线程甚至是并行但最重要的是   最好的方式

是的,您可以使其并行并控制您使用的资源。

  

只要它没有那么慢,我就不会太担心速度   现在,但我不想过度使用CPU等设备的资源   试图加快速度

你应该能够实现这一点,并且相当好地配置

好的,所以有很多方法可以做到这一点。以下是一些需要考虑的事项

  • 您有1000个IO bound任务(适用于CPU bound任务)
  • 使用这么多文件,您需要一些并行性,并能够配置并发任务量。
  • 希望以async / await模式执行此操作,这样您就不会在IO完成端口上浪费系统资源或粉碎CPU

一些直接的解决方案

  • 任务以及asnyc / await模式中的WaitAll,这是一个很好的方法,但是限制并发任务有点棘手。
  • 您拥有Parallel.ForEachParallel.For,这有一个很好的方法来限制并发工作负载,但它不适合IO绑定任务
  • 或者您可能考虑的其他选项是 Microsoft Dataflow (Task Parallel Library),我最近很喜欢这些库,因为它们可以为您提供两全其美的优势。
  

请注意:还有很多其他方法

所以Parallel.ForEach使用线程池。此外, IO绑定操作将阻止那些等待设备响应并占用资源的线程。一般的经验法则是

  • 如果您有 CPU绑定代码,Parallel.ForEach是合适的;
  • 虽然如果您有 IO绑定代码, Asynchrony 是合适的。

在这种情况下,下载文件显然是 I / O ,有DownloadFileAsync版本和1000个要下载的文件,因此您最好使用async / await模式和某些类型的并发任务限制

以下是如何实现此目标的一个非常基本的示例

鉴于

public class WorkLoad
{
    public string Url {get;set;}
    public string FileName {get;set;}

}

数据流示例

public async Task DoWorkLoads(List<WorkLoad> workloads)
{
   var options = new ExecutionDataflowBlockOptions
                     {
                        // add pepper and salt to taste
                        MaxDegreeOfParallelism = 50
                     };

   // create an action block
   var block = new ActionBlock<WorkLoad>(MyMethodAsync, options);

   // Queue them up
   foreach (var workLoad in workloads)
      block.Post(workLoad );

   // wait for them to finish
   block.Complete();
   await block.Completion;

}

...

// Notice we are using the async / await pattern
public async Task MyMethodAsync(WorkLoad workLoad)
{

    try
    {
        Console.WriteLine("Downloading: " + workLoad.Url);
        await client.DownloadFileAsync(workLoad.Url, workLoad.FileName);
    }
    catch (Exception)
    {
        // probably best to add some error checking some how
    }
}

摘要

这种方法为您提供了 Asynchrony ,它还为您提供了MaxDegreeOfParallelism,它不会浪费资源,并且让 IO 成为 IO

  

*免责声明,DataFlow可能不是您想要的地方,但我只是认为id会为您提供更多信息

     

*免责声明2 ,上述代码尚未经过测试,我会认真考虑先研究这项技术并彻底尽职尽责。

Loosely related demo here

答案 1 :(得分:1)

将您的功能标记为async并使用DownloadFileAsync保存文件。在返回之前,将任务列表捕获到一个新列表中,并await列出Task.WhenAll(yourTasks)列表。

答案 2 :(得分:0)

您可以使用Parallel.ForEach并行下载文件。我过去曾经使用过类似的东西。

    using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace FileDownloader
{
    class Program
    {
        static void Main(string[] args)
        {
            List allUrls = GetUrls().Select(x=>x.Trim()).ToList();

            Parallel.ForEach(allUrls, new ParallelOptions() { MaxDegreeOfParallelism = 10 }, url =>
            {
                try
                {
                    WebRequest request = WebRequest.Create(url);
                    WebResponse response = request.GetResponse();
                    string originalFileName = response.ResponseUri.AbsolutePath.Substring(response.ResponseUri.AbsolutePath.LastIndexOf("/") + 1);
                    Stream streamWithFileBody = response.GetResponseStream();
                    using (Stream output = File.OpenWrite(@"C:\Ebooks_New\" + originalFileName))
                    {
                        streamWithFileBody.CopyTo(output);
                    }

                    Console.WriteLine("Downloded : " + originalFileName);
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Unable to Download : " + ex.ToString());

                }
            });

            Console.WriteLine("Finished : ************************");
            Console.ReadKey();
        }

        public static List GetUrls()
        {
            return new List() // Put list of URLs here
            {
                "http://ligman.me/1IW1oab  ",
    "http://ligman.me/1Uixtlq  ",
    "http://ligman.me/1R9Ubgt  ",
    "http://ligman.me/1H4VXHT  ",
    "http://ligman.me/1f8XUKy  ",
    "http://ligman.me/1HBEUPi  ",
    "http://ligman.me/1NDTZR4  ",
    "http://ligman.me/1Uiy2f9  ",
    "http://ligman.me/1epZ0QU  ",
    "http://ligman.me/1JIhgjA  ",
    "http://ligman.me/1CQX5uG  ",
   }
  }
 }
}