C#开发基础之多线程技术应用之并行下载并通知运行状态
创作时间:
2025-01-22 01:56:29
作者:
@小白创作中心
C#开发基础之多线程技术应用之并行下载并通知运行状态
在处理大量文件下载或并行任务时,多线程技术是提高效率的关键工具。通过将大任务拆分成多个小任务并行执行,可以显著缩短完成时间。本文将介绍在C#中实现多线程并行下载的两种方法,并展示如何实时报告任务进度。
场景描述
想象一下,你需要下载1,000个文件或同时处理多个任务。在传统的单线程模型中,这将是一个漫长的等待过程。但通过多线程,我们可以将这个大任务拆分成多个小任务并行执行,从而大大缩短完成时间,提高整体效率。
然而,仅仅完成任务是不够的。为了确保用户和其他相关方实时了解进展情况,我们需要一个高效的进度跟踪和报告机制。这可以通过建立实时监控系统或利用进度条、日志和通知来实现。这样用户,都可以在任何时候了解项目的当前状态和预期进度。
下面就思考两种实现方式:多线程和并行库的用法。主要是体会使用模型的使用。
多线程处理实现过程
示例代码:
using System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static int currentFile = 0;
static object lockObject = new object();
static void Main(string[] args)
{
const int NUM_FILES = 1000;
const int NUM_THREADS = 20;
// 创建一个计数器,以便在所有线程完成后更新状态。
CountdownEvent countdown = new CountdownEvent(NUM_THREADS);
// 创建20个下载线程
for (int i = 0; i < NUM_THREADS; i++)
{
int threadIndex = i;
Task.Run(() =>
{
// 模拟下载过程
for (int j = threadIndex; j < NUM_FILES; j += NUM_THREADS)
{
DownloadFile(j);
ReportProgress(NUM_FILES); // 报告下载进度
}
// 当前线程完成下载,向计数器发信号。
countdown.Signal();
});
}
// 等待所有线程完成
countdown.Wait();
// 所有线程都已完成,将状态标记为已完成。
Console.WriteLine("所有文件下载已完成!");
}
static void DownloadFile(int fileIndex)
{
// 模拟下载过程
Thread.Sleep(100); // 假设每个文件需要10毫秒下载
Console.WriteLine($"文件 #{fileIndex} 已下载完毕!");
}
static void ReportProgress(int NUM_FILES)
{
lock(lockObject)
{
int current = Interlocked.Increment(ref currentFile);
Console.WriteLine($"当前进度:{current}/{NUM_FILES}");
}
}
}
- 定义常量:
NUM_FILES表示总文件数量,这里设定为1000。NUM_THREADS表示线程数量,这里设定为20。 - 创建一个
CountdownEvent对象countdown,用于在所有线程完成后更新状态。 - 创建20个下载线程:使用
Task.Run()创建一个任务,并在每个任务中执行相应的操作,每个线程根据索引threadIndex来决定从哪个文件开始下载,通过循环递增NUM_THREADS来实现线程间的文件分配。 在循环中调用DownloadFile()方法来模拟下载文件,并在下载完成后调用ReportProgress()方法报告下载进度。 当线程完成下载后,通过countdown.Signal()向计数器发信号。 - 使用
countdown.Wait()等待所有线程完成。 - 所有线程都已完成,输出提示信息:“所有文件下载已完成!”
DownloadFile()方法模拟文件下载过程:使用Thread.Sleep()方法来模拟下载耗时,这里假设每个文件需要100毫秒下载。输出下载完毕的文件信息。ReportProgress()方法用于报告下载进度:使用lock语句加锁,确保多个线程同时操作currentFile变量时不会产生竞争条件。使用Interlocked.Increment()原子地递增currentFile变量,获取当前下载的文件数。输出当前下载进度信息。
小结
总体而言,该程序通过创建多个线程来并行下载文件,并使用计数器来跟踪所有线程的完成状态。每个线程负责下载部分文件,并在完成后报告当前的下载进度。最后,当所有线程都完成时,输出下载完成的提示信息。
使用并行库的处理过程
示例代码:
using System;
using System.Threading.Tasks;
using System.Collections.Concurrent;
using System.Diagnostics;
namespace ParallelApp
{
class Program
{
static int currentFile = 0;
static object lockObject = new object();
static void Main(string[] args)
{
const int NUM_FILES = 1000;
// 使用ParallelOptions来跟踪并行任务的进度
var parallelOptions = new ParallelOptions
{
MaxDegreeOfParallelism = 20 // 设置最大并行度
};
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
// 使用Parallel.ForEach并行下载文件
Parallel.ForEach(
Partitioner.Create(0, NUM_FILES), // 使用分区器创建任务范围
parallelOptions,
(range, loopState) =>
{
for (int j = range.Item1; j < range.Item2; j++)
{
DownloadFile(j);
ReportProgress(NUM_FILES); // 报告下载进度
}
});
stopWatch.Stop();
// 所有任务完成后输出信息
Console.WriteLine("所有文件下载已完成!" + stopWatch.ElapsedMilliseconds + "ms");
}
static void DownloadFile(int fileIndex)
{
// 模拟下载过程
Task.Delay(100).Wait(); // 假设每个文件需要100毫秒下载
Console.WriteLine($"文件 #{fileIndex} 已下载完毕!");
}
static void ReportProgress(int NUM_FILES)
{
lock (lockObject)
{
int current = Interlocked.Increment(ref currentFile);
Console.WriteLine($"当前进度:{current}/{NUM_FILES}");
}
}
}
}
- 初始化并行任务:使用并行库,你可以利用
Parallel.For或Parallel.ForEach来简化并行任务的创建和管理。这些方法会自动处理任务的分发和管理,无需手动管理线程。 - 分发任务:
Parallel.For或Parallel.ForEach会根据可用的处理器核心数或任务的工作量自动分发任务。你只需指定任务的起始和结束范围。 - 报告进度:由于
Parallel类提供了内置的机制来跟踪任务的进度,所以你可能需要使用ParallelOptions和ParallelLoopState来跟踪和报告任务的进度。
小结:
在这个版本中,我们使用Parallel.ForEach来并行处理文件的下载任务。我们使用了Partitioner.Create来创建任务的范围,并使用ParallelOptions来控制并行度。此外,进度报告也被稍微简化,因为Parallel类本身提供了一个更简洁的方法来处理这种情况。
参考文档:
热门推荐
甜蜜的艺术:甜品制作与品鉴指南
狗狗关节保健食品选购指南:常见的关节保养成分!
足球赛事控球率对比分析揭示战术优势与比赛走向的重要性
Excel版本转换完全指南:从基础操作到实际应用
煤矿工人在多家煤矿“搬过砖”,工伤责任谁来担?
公积金的计算方式是什么?
春夏秋冬与五行对应
崩坏星穹铁道3.0天谴之矛BOSS打法攻略 天谴之矛如何打[多图]
嵌入式直饮机是什么意思 嵌入式直饮机优缺点有哪些
“奥本海默:原子建筑师的道德困境——科学的伦理责任”
从马王堆出土文物窥探汉代饮食文化
小猫眼睛流脓封眼能自愈吗?我们能做些什么?
提升网络速度与稳定性的实用技巧分享与优化方法总结
《饥荒》远古织影者攻略:两种形态弱点解析与应对策略
森林瀑布:水与绿的交响,生态与心灵的交融
夫妻备孕基因检测项目有哪些,该如何做?
二手房交易份额开始反哺新房
这两处长息肉,发现后到底要不要割?
一文了解游戏中的“玩家作弊”和“黑产工作室”
如何建立一个稳固且持久的爱情关系
连续三年全省第一 西双版纳打造云南省水产种业高地
报告格式与模板:专业范文示例
打豆浆后的豆渣能吃吗?营养价值与食用方法全解析
转型金融标准呼之欲出 为钢铁行业低碳转型解决融资难题
开学了,早餐这样做,简单省事,营养又美味
中英街|内地人申请沙头角通行证,周日起可“全程网办”
《守望先锋2》推出6v6试验模式:2-2-2预设职责阵容限时开启
C罗:足坛摇钱树!身兼4职,个人品牌价值暴增至64亿元!
如何识别并有效减轻男性的焦虑症状?
抽烟肺部左侧疼痛怎么办?五种有效治疗方法