线程系列02,多个线程同时处理一个耗时较长的任务以节省时间
线程 处理 一个 系列 任务 多个 02 同时
2023-09-11 14:16:51 时间
当面对一个耗时较长的任务时,我们可以把这个任务切分成多个部分,然后同时交给多个线程处理。
□ 统计字节数组一个比较耗时的方式
以下来统计一个字节数组的大小。
class Program
{static byte[] values = new byte[500000000];static void Main(string[] args){GenerateByteArray();Console.WriteLine("正在统计字节数");
Stopwatch watch = new Stopwatch();
watch.Start();long total = 0;
for (int i = 0; i < values.Length; i++){total += values[i];}watch.Stop();Console.WriteLine("统计结果为:" + total);
Console.WriteLine("计算时间为:" + watch.Elapsed);
}static void GenerateByteArray(){var r = new Random(987);
for (int i = 0; i < values.Length; i++){values[i] = (byte)r.Next(10);
}}}
如果把统计工作同时交给多个线程,是否可以把统计时间省下来呢?
□ 同时使用多个线程
现在要对"统计字节数组大小"这个任务进行均分、切分。首先面临的问题是:按什么标准均分?
--这个完全是靠个人喜好,可以让2个线程,3个线程......来处理。在这里,就根据CPU的数量来均分,因为CPU的数量可以通过Environment.ProcessorCount获得。
面临的第二问题是:均分什么?
--比如有4个CPU
--那可以把任务分成4个线程同时处理
--把字节数组的长度均分,比如字节数组的长度是1000,均分成4段,每段长度为250
--把字节数组的大小分成4个放一个数组里,即[sum1, sum2, sum3, sum4],所有的元素加起来就是字节数组的总大小
class Program
{static byte[] values = new byte[500000000];//分段统计的大小放该数组,比如分成4等份,[10000,10005,10008,10009]
private static long[] partialSum;//把values数组长度均等分,比如长度1000,分成4粉,那partialSize就是250
private static int partialSize;static void Main(string[] args){//根据CPU的数量确定数组的长度
partialSum = new long[Environment.ProcessorCount];//根据CPU的数量确定数组长度均等分
partialSize = values.Length/Environment.ProcessorCount;GenerateByteArray();Console.WriteLine("正在统计字节数");
Stopwatch watch = new Stopwatch();
watch.Start();long total = 0;
for (int i = 0; i < values.Length; i++){total += values[i];}watch.Stop();Console.WriteLine("统计结果为:" + total);
Console.WriteLine("计算时间为:" + watch.Elapsed);
Console.WriteLine();watch.Reset();watch.Start();Thread[] threads = new Thread[Environment.ProcessorCount];
for (int i = 0; i < Environment.ProcessorCount; i++){threads[i] = new Thread(SumPartial);
threads[i].Start(i);}//保证一个线程结束再执行下一个线程
for (int i = 0; i < Environment.ProcessorCount; i++){threads[i].Join();}//统计总大小
long total2 = 0;
for (int i = 0; i < Environment.ProcessorCount; i++){total2 += partialSum[i];}watch.Stop();Console.WriteLine("使用分段线程统计的大小:" + total2);
Console.WriteLine("计算时间为:" + watch.Elapsed);
}/// <summary>
/// 分段统计字节数组的大小
/// </summary>
/// <param name="partialNumber">比如有4个CPU,partialNumber可能的值是0, 1, 2, 3</param>
static void SumPartial(object partialNumber){long sum = 0;
int partialNumberAsInt = (int)partialNumber;int baseIndex = partialNumberAsInt * partialSize;
for (int i = baseIndex; i < baseIndex + partialSize; i++){sum += values[i];}partialSum[partialNumberAsInt] = sum;}/// <summary>
/// 创建字节数组
/// </summary>
static void GenerateByteArray(){var r = new Random(987);
for (int i = 0; i < values.Length; i++){values[i] = (byte)r.Next(10);
}}}
以上,统计字节数组大小的方式倒不是最重要的,线程部分才是重点:
○ 有几个CPU,就有几个线程
○ 线程的实例方法Start可以传递object类型的参数
○ 线程的实例方法Join,用来保证执行完上一个线程再执行下一个线程
在这里,使用多线程同时处理一个任务,效率差不多提高了2.6倍!
总结:
○ 对于一个比较耗时的任务可以同时交给多个线程处理
○ 线程的实例方法Join保证执行完上一个线程再执行下一个线程
线程系列包括:
线程系列01,前台线程,后台线程,线程同步
线程系列02,多个线程同时处理一个耗时较长的任务以节省时间
线程系列03,多线程共享数据,多线程不共享数据
线程系列04,传递数据给线程,线程命名,线程异常处理,线程池
线程系列05,手动结束线程
线程系列06,通过CLR代码查看线程池及其线程
线程系列07,使用lock语句块或Interlocked类型方法保证自增变量的数据同步
线程系列08,实现线程锁的各种方式,使用lock,Montor,Mutex,Semaphore以及线程死锁
线程系列10,无需显式调用线程的情形
相关文章
- 线程执行者(六)运行多个任务并处理所有结果
- python线程池
- 【并发技术16】线程同步工具Exchanger的使用
- 基于SmartThreadPool线程池技术实现多任务批量处理
- 线程组之间的JMeter传递变量
- 关于多线程编程您不知道的 5 件事 有关高性能线程处理的微妙之处
- Java线程监听,意外退出线程后自动重启
- HashMap在高并发下如果没有处理线程安全会有怎样的安全隐患,具体表现是什么
- Java线程组(ThreadGroup)使用
- 【完整代码】使用Semaphore实现线程的交替执行打印 A1B2C3D4E5
- 多线程之线程池-当任务渐增时的处理-各个参数的含义- 阿里,美团,京东面试题目
- 消息队列与线程处理
- 【Kotlin 协程】协程的挂起和恢复 ② ( 协程挂起 和 线程阻塞 对比 )
- 【Android 异步操作】线程池 ( 线程池 execute 方法源码解析 )
- Java线程学习笔记(两) 线程异常处理
- 子进程和线程
- Android JNI学习-线程相关操作