在C#开发中,当我们需要处理大量重复的计算任务、批量数据遍历或者多个独立子任务时,使用Parallel类进行并行编程可以充分利用多核CPU的性能,大幅缩短程序执行时间。Parallel类位于System.Threading.Tasks命名空间下,提供了简单的并行执行逻辑,不需要开发者手动管理线程的创建和调度。
Parallel并行编程的核心方法
Parallel类主要提供三个常用的静态方法,分别对应不同的使用场景,开发者可以根据任务类型选择合适的方法。
1. Parallel.Invoke
该方法用于并行执行多个独立的委托任务,适合需要同时运行多个互不依赖的子任务的场景。传入的委托数组中的每个委托都会分配到不同的线程上执行,所有任务完成后方法才会返回。
using System;
using System.Threading.Tasks;
class Program
{
static void Main()
{
// 并行执行三个独立的任务
Parallel.Invoke(
() => TaskOne(),
() => TaskTwo(),
() => TaskThree()
);
Console.WriteLine("所有任务执行完成");
}
static void TaskOne()
{
Console.WriteLine("任务一开始执行");
// 模拟任务耗时
System.Threading.Thread.Sleep(1000);
Console.WriteLine("任务一执行完成");
}
static void TaskTwo()
{
Console.WriteLine("任务二开始执行");
System.Threading.Thread.Sleep(1500);
Console.WriteLine("任务二执行完成");
}
static void TaskThree()
{
Console.WriteLine("任务三开始执行");
System.Threading.Thread.Sleep(800);
Console.WriteLine("任务三执行完成");
}
}
2. Parallel.For
该方法用于并行执行循环操作,替代传统的for循环,适合需要对连续的整数区间执行相同操作的场景。方法会自动将循环区间拆分成多个子区间,分配到不同线程执行。
using System;
using System.Threading.Tasks;
class Program
{
static void Main()
{
int totalCount = 100;
int sum = 0;
// 并行执行0到totalCount-1的循环
Parallel.For(0, totalCount, i =>
{
// 每个迭代执行的计算逻辑
System.Threading.Interlocked.Add(ref sum, i);
});
Console.WriteLine($"0到{totalCount-1}的总和为:{sum}");
}
}
这里使用System.Threading.Interlocked.Add方法是因为多个线程会同时修改sum变量,需要保证操作的原子性,避免出现数据不一致的问题。
3. Parallel.ForEach
该方法用于并行遍历集合,替代传统的foreach循环,适合需要对集合中的每个元素执行相同操作的场景。集合可以是数组、List或者其他实现了IEnumerable接口的类型。
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
class Program
{
static void Main()
{
List<string> dataList = new List<string>
{
"数据1", "数据2", "数据3", "数据4", "数据5"
};
// 并行遍历集合
Parallel.ForEach(dataList, item =>
{
Console.WriteLine($"正在处理:{item}");
// 模拟处理每个数据的耗时
System.Threading.Thread.Sleep(500);
Console.WriteLine($"{item}处理完成");
});
Console.WriteLine("所有数据处理完成");
}
}
完整项目实例:批量数据计算
下面提供一个完整的控制台项目实例,模拟批量处理用户数据的场景,对比单线程和并行执行的耗时差异,完整源码可以直接复制运行。
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
namespace ParallelDemo
{
class User
{
public int Id { get; set; }
public string Name { get; set; }
public int Score { get; set; }
}
class Program
{
static void Main()
{
// 生成1000条测试用户数据
List<User> userList = new List<User>();
for (int i = 0; i < 1000; i++)
{
userList.Add(new User
{
Id = i,
Name = $"用户{i}",
Score = new Random().Next(0, 100)
});
}
// 单线程处理数据
Stopwatch singleWatch = Stopwatch.StartNew();
int singleSum = 0;
foreach (var user in userList)
{
// 模拟每个用户数据的计算耗时
System.Threading.Thread.Sleep(10);
singleSum += user.Score;
}
singleWatch.Stop();
Console.WriteLine($"单线程处理完成,总分数:{singleSum},耗时:{singleWatch.ElapsedMilliseconds}毫秒");
// 并行处理数据
Stopwatch parallelWatch = Stopwatch.StartNew();
int parallelSum = 0;
Parallel.ForEach(userList, user =>
{
// 模拟每个用户数据的计算耗时
System.Threading.Thread.Sleep(10);
System.Threading.Interlocked.Add(ref parallelSum, user.Score);
});
parallelWatch.Stop();
Console.WriteLine($"并行处理完成,总分数:{parallelSum},耗时:{parallelWatch.ElapsedMilliseconds}毫秒");
}
}
}
运行上述代码后,可以看到并行处理的耗时明显低于单线程处理,尤其是在数据量更大、单个任务耗时更长的情况下,性能提升会更明显。
并行编程的注意事项
- 不是所有场景都适合用并行编程,如果单个任务耗时很短,线程调度的开销反而会抵消并行带来的性能提升。
- 并行执行的任务如果存在共享资源的修改,需要使用锁或者原子操作保证线程安全,避免出现数据竞争问题。
- Parallel的方法默认会等待所有任务完成后才返回,如果需要取消执行,可以传入
ParallelOptions对象设置取消令牌。 - 并行度不是越高越好,默认情况下Parallel会根据CPU核心数自动调整并行度,也可以手动设置
MaxDegreeOfParallelism属性控制最大并行数量。
并行编程的核心是合理拆分任务,保证任务之间尽量独立,减少线程间的同步开销,才能最大化发挥多核CPU的性能优势。
C#_Parallel并行编程Parallel_ForParallel_ForEachTask修改时间:2026-06-28 15:15:56