c# 并行计算
目录
一、并行执行效率对比
数据源
Data = new List<int>() { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; bool ShowProcessExecution = true;
For循环
DateTime dt1 = DateTime.Now;
for(int i=0 ; i<data.Count;i++)
{
Thread.Sleep(500);
if (ShowProcessExecution)
Console.WriteLine(data[i]);
}
DateTime dt2 = DateTime.Now;
Console.WriteLine("普通For运行时常:{0}毫秒", (dt2 - dt1).TotalMilliseconds);
Foreach
DateTime dt1 = DateTime.Now;
foreach(var i in data)
{
Thread.Sleep(500);
if (ShowProcessExecution)
Console.WriteLine(data[i]);
}
DateTime dt2 = DateTime.Now;
Console.WriteLine("普通Foreach运行时常:{0}毫秒", (dt2 - dt1).TotalMilliseconds);
并行For循环
DateTime dt1 = DateTime.Now;
Parallel.For(0, data.Count, (i) =>
{
Thread.Sleep(500);
if (ShowProcessExecution)
Console.WriteLine(data[i]);
});
DateTime dt2 = DateTime.Now;
Console.WriteLine("并行For运行时常:{0}毫秒", (dt2 - dt1).TotalMilliseconds);
并行Foreach
DateTime dt1 = DateTime.Now;
Parallel.ForEach(data, (i) =>
{
Thread.Sleep(500);
if (ShowProcessExecution)
Console.WriteLine(data[i]);
});
DateTime dt2 = DateTime.Now;
Console.WriteLine("并行Foreach运行时常:{0}毫秒", (dt2 - dt1).TotalMilliseconds);
效率对比
普通For运行时常:5002毫秒
普通Foreach运行时常:5000毫秒
并行For运行时常:2009毫秒
并行Foreach运行时常:1525毫秒
二、并行中断
Break中断
Parallel.For(0, data.Count, (i, LoopState) =>
{
if (data[i] > 6)
{
LoopState.Break();
}
Thread.Sleep(500);
Console.WriteLine(data[i]);
});
Console.WriteLine("Stop执行结束。");
Stop中断
Parallel.For(0, data.Count, (i, LoopState) =>
{
if (data[i] > 6)
{
LoopState.Stop();
}
Thread.Sleep(500);
Console.WriteLine(data[i]);
});
Console.WriteLine("Stop执行结束。");
三、为数组/集合添加项
List是非线程安全的类,多线程操作的时候可能会出现报错
可以使用System.Collections.Concurrent命名空间下
ConcurrentQueue和ConcurrentStack线程安全的类来操作
List<int> data = new List<int>();
Parallel.For(0,Program.Data.Count, (i) =>
{
if(Program.Data[i]%2==0)
data.Add(Program.Data[i]);
});
Console.WriteLine("执行完成For.");
ConcurrentQueue
ConcurrentStack<int> data = new ConcurrentStack<int>();
Parallel.ForEach(Program.Data, (i) =>
{
if (Program.Data[i] % 2 == 0)
data.Push(Program.Data[i]);//将对象压入栈中
});
int R;
while (data.TryPop(out R))//弹出栈顶对象
{
Console.WriteLine(R);
}
Console.WriteLine("执行完成ForEach.");
ConcurrentStack
ConcurrentStack<int> data = new ConcurrentStack<int>();
Parallel.ForEach(Program.Data, (i) =>
{
if (Program.Data[i] % 2 == 0)
data.Push(Program.Data[i]);//将对象压入栈中
});
int R;
while (data.TryPop(out R))//弹出栈顶对象
{
Console.WriteLine(R);
}
Console.WriteLine("执行完成ForEach.");
四、并行运算中的局部变量
Foreach局部变量
long total = 0;
// data数据源 int为 i 的类型, long 为 局部变量curNumber的类型
Parallel.ForEach<int,long>(data,
() => 0, // curNumber初始化0
// 为每个迭代调用一次的委托,i是当前索引,LoopState是循环状态,curNumber为局部变量名
(i, LoopState, curNumber) =>
{
curNumber += i; // 修改局部变量
return curNumber; // 传递参数给下一个迭代
},
//对每个线程结果执行的最后操作,这里是将所有的结果相加
(curNumber) => Interlocked.Add(ref total, curNumber)
);
Console.WriteLine(total);
}
For局部变量
long total = 0;
Parallel.For<long>(0, // For循环的起点
data.Count, // For循环的终点
() => 0, // 初始化局部变量的方法(long),既为下面的curNumber的初值
// 为每个迭代调用一次的委托,i是当前索引,LoopState是循环状态,curNumber为局部变量名
(i, LoopState, curNumber) =>
{
curNumber += data[i]; // 修改局部变量
return curNumber; // 传递参数给下一个迭代
},
//对每个线程结果执行的最后操作,这里是将所有的结果相加
(curNumber) => Interlocked.Add(ref total, curNumber)
);
Console.WriteLine(total);
五、PLinq并行
var source = Enumerable.Range(1, 10000);
ConcurrentBag<int> concurrentBag = new ConcurrentBag<int>();
//查询结果按source中的顺序排序
var evenNums = from num in source.AsParallel().AsOrdered()
// where num % 100 == 0
orderby num
select num;
evenNums.ForAll((e) => concurrentBag.Add(e));
//ForAll的使用
var query = from num in source.AsParallel()
where num % 100 == 0
select num;
query.ForAll((e) => concurrentBag.Add(e));