代码改变世界

一个简单的利用 WebClient 异步下载的示例(三)

2018-09-12 19:31  音乐让我说  阅读(256)  评论(0编辑  收藏  举报

继续上一篇 一个简单的利用 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 个任务都非常快速地完成了,也要等在那里。下篇文章,我们将再次完善它。

谢谢浏览!