zoukankan      html  css  js  c++  java
  • 一个简单的利用 WebClient 异步下载的示例(三)

    继续上一篇 一个简单的利用 WebClient 异步下载的示例(二) 后,继续优化它。

    1. 直接贴代码了:

    DownloadEntry:

        public class DownloadEntry
        {
            public string Url { get; set; }
    
            public string Path { get; set; }
    
            /// <summary>
            /// 当前处理的数据
            /// </summary>
            public object Data { get; set; }
    
            public DownloadEntry(string url, string savedPath)
                : this(url, savedPath, null)
            {
    
            }
    
            public DownloadEntry(string url, string savedPath, object data)
            {
                Url = url;
                Path = savedPath;
                Data = data;
            }
        }

    SkyParallelWebClient 类:

        /// <summary>
        /// 并行的 WebClient
        /// </summary>
        public class SkyParallelWebClient
        {
            ConcurrentQueue<DownloadEntry> OptionDataList = new ConcurrentQueue<DownloadEntry>();
    
            public SkyParallelWebClient(ICollection<DownloadEntry> downloadConfigs)
            {
                if (downloadConfigs == null)
                {
                    throw new ArgumentNullException("downloadConfigs");
                }
                foreach (var item in downloadConfigs)
                {
                    OptionDataList.Enqueue(item);
                }
            }
    
            public bool TryStart(int parallelCount)
            {
                string errorMessage;
                return TryStart(parallelCount, out errorMessage);
            }
    
            public bool TryStart(int parallelCount, out string errorMessage)
            {
                try
                {
                    StartCore(parallelCount);
                    errorMessage = null;
                    return true;
                }
                catch (Exception ex)
                {
                    errorMessage = ex.Message;
                    return false;
                }
            }
    
            protected void StartCore(int takeCount)
            {
                if (OptionDataList.Count == 0)
                {
                    return;
                }
                IList<Task> processingTasks = new List<Task>();
                for (int i = 0; i < takeCount; i++)
                {
                    if (OptionDataList.Count == 0)
                    {
                        break;
                    }
                    DownloadEntry downloadEntry;
                    if (!OptionDataList.TryDequeue(out downloadEntry))
                    {
                        break;
                    }
                    var task = Task.Factory.StartNew((data) =>
                    {
                        DownloadEntry temp = data as DownloadEntry;
                        if (downloadEntry == null)
                            return;
                        DownloadFile(temp);
                    }, downloadEntry);
                    processingTasks.Add(task);
                }
                Task.WaitAll(processingTasks.ToArray());
                if (OptionDataList.Count > 0)
                {
                    StartCore(takeCount);
                }
            }
    
            private static void DownloadFile(DownloadEntry downloadEntry)
            {
                using (WebClient webClient = new WebClient())
                {
                    //set this to null if there is no proxy
                    webClient.Proxy = null;
    
                    webClient.DownloadFile(new Uri(downloadEntry.Url), downloadEntry.Path);
                }
            }
        }

     客户端测试代码:

            private void btnRunByWebClient_Click(object sender, EventArgs e)
            {
                WhenAllDownloading();
                var ids = GetDownloadIds();
                List<DownloadEntry> downloadConfigs = new List<DownloadEntry>();
                Random rd = new Random();
                foreach (var id in ids)
                {
                    downloadConfigs.Add(new DownloadEntry(TaskDemo101.GetRandomUrl(rd), TaskDemo101.GetSavedFileFullName(), id));
                }
                ThreadPool.QueueUserWorkItem(new WaitCallback(AsyncRunSkyParallelWebClient), downloadConfigs);
            }
    
            private void AsyncRunSkyParallelWebClient(object state)
            {
                SkyParallelWebClient skyParallelWebClient = new SkyParallelWebClient((List<DownloadEntry>)state);
                string errorMessage;
                if (!skyParallelWebClient.TryStart(20, out errorMessage))
                {
                    MessageBox.Show(errorMessage);
                    return;
                }
                WhenAllDownloaded();
            }

    2. 效果图

    由于并行后,无法统计下载进度,所以没有进度条了。注意:每一项完成后,没有日志,也就是说下面的 “编号 99 下载 True”是不会有的!

    3. 总结

    以上测试可以解决并行下载的任务,且体验相对来说比较好。但有一个不完美的地方,就是该任务以一定量(比如:20个)任务为一个单元,只要这个单元中有一个任务耗费了太多太多时间,即使其它 19 个任务都非常快速地完成了,也要等在那里。下篇文章,我们将再次完善它。

    谢谢浏览!

  • 相关阅读:
    python库--pandas--Series.str--字符串处理
    前端--jstree--异步加载数据
    python库--flask--创建嵌套蓝图
    Git--生成公钥和私钥并添加gitlab访问权限
    es查询--请求body
    python生成时间序列(date_range)
    golang使用组合完成伪继承
    golang interface类型的动态绑定
    ruby环境安装草稿
    openfire
  • 原文地址:https://www.cnblogs.com/Music/p/WebClient-DownloadFileAsync3.html
Copyright © 2011-2022 走看看