C# 使用Parallel去执行并行下载

直接上代码:

csharp 复制代码
	//最大线程下载数量
     ParallelOptions options = new ParallelOptions
        {
            MaxDegreeOfParallelism = 5
        };
     public async Task DownloadMusicUrl(List<MusicTags> musicTags)
        {
            DateTime currentTime = DateTime.Now;
            DateTime startTime = new DateTime(1970, 1, 1);
            TimeSpan timeSpan = currentTime - startTime;
            string timestamp = ((long)timeSpan.TotalMilliseconds).ToString();
            string type = string.Empty;
            if (this.mp3.Checked) type = this.mp3.Text;
            if (this.flac.Checked) type = this.flac.Text;
            if (this.mv.Checked) type = this.mv.Text;

             并行下载URL列表中的所有文件
            List<Task> downloadTasks = new List<Task>();
            Parallel.ForEach(musicTags, options, tag =>
                {
                    Task task = Download(tag, timestamp, type);
                    downloadTasks.Add(task); // 将下载任务的 Task 添加到 downloadTasks 列表中
                    await Task.Delay(500);
                });
            await Task.WhenAll(downloadTasks C#有偿Q群:927860652); // 等待所有下载任务完成

        }

这里切记先用 Task task = Download(tag, timestamp, type);把任务添加到集合,不要直接await在ForEach的委托里面执行代码,这样会出现一些无法控制的bug,任务添加完成后,在最外面await Task.WhenAll(downloadTasks); 通过这个等待下载完成。

这样就可以很好的控制并行下载呢。

csharp 复制代码
       public async Task Download(MusicTags tag, string timestamp, string type = "mp3")
        {
            using (WebClient webClient = new WebClient())
            {
                try
                {
                    string solutionPath = Path.GetDirectoryName(Path.GetDirectoryName(Path.GetDirectoryName(Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory))));
                    string folderPath = Path.Combine(solutionPath, "资源下载", DateTime.Now.ToString("yyyyMMdd"), timestamp);
                    gloFolderPath = folderPath;
                    Directory.CreateDirectory(folderPath);
                    string name = $"{tag.baseMusic.SongTitle}-{tag.baseMusic.Singer}.{type}";
                    // 设置下载完成后保存的本地路径和文件名
                    string localPath = Path.Combine(folderPath, name); // 替换为保存路径

                    // 订阅 DownloadProgressChanged 事件来更新进度条
                    webClient.DownloadProgressChanged += (s, args) =>
                    {
                        int progress = args.ProgressPercentage;
                        long bytesReceived = args.BytesReceived;
                        long totalBytesToReceive = args.TotalBytesToReceive;

                        UpdateProgressBar(progress, bytesReceived, totalBytesToReceive, name);
                    };

                    await webClient.DownloadFileTaskAsync(new Uri(tag.tag), localPath);

                    //Console.WriteLine("音乐下载完成,保存路径:" + localPath);
                }
                catch (Exception ex)
                {
                    Console.WriteLine("音乐下载失败:" + ex.Message + ex.StackTrace);
                }
            }

            // 下载完成后,更新进度条为 100%
            UpdateProgressBar(100, 0, 0, "下载完成");
            AppendLog($"{tag.baseMusic.SongTitle}-{tag.baseMusic.Singer} 已下载");
        }
相关推荐
j7~15 分钟前
【Linux】二十六.线程篇三《Linux多线程编程:线程控制、线程ID以及进程地址空间分布、线程局部存储__thread以及clone系统调用》---详解
linux·运维·服务器·开发语言·c++·多线程编辑·线程的控制
维吉斯蔡8 小时前
【VS Code / Cursor】文件夹右键快捷打开与文件类型自动关联
开发语言·程序人生·学习方法
蓝斯4978 小时前
[原创]《C#高级GDI+实战:从零开发一个流程图》第章:增加贝塞尔曲线,上、下、左、右连接点
java·c#·流程图
luj_176810 小时前
星火科技助力边远地区防病攻坚
c语言·开发语言·c++·经验分享·算法
always_TT10 小时前
【Python 日志记录:logging 模块入门】
开发语言·python·php
xcLeigh10 小时前
Go入门:变量声明的五种方式详解
java·开发语言·golang
zmzb010311 小时前
C++课后习题训练记录Day175
开发语言·c++
脱胎换骨-军哥11 小时前
C++ 代码规范与格式化指南
开发语言·c++·代码规范
枕星而眠12 小时前
C++ STL Map容器完全指南:从有序红黑树到无序哈希表
java·开发语言
小白白36113 小时前
Pixelorama怎么用?像素画绘制和动画制作入门
windows