随着多核时代的到来,并行开发越来越展示出它的强大威力。在了解并行开发之前,我们先来了解两个法则“Amdahl”和“Gustafson”
Amdahl
amdahl法则,通过以下公式预测多处理器系统的最大理论性能提升(即加速比,speedup).这个公式也可以应用于运行多核微处理器上的并行算法
最大加速比(倍数)=1/((1-p)+(p/N))
其中:
P 表示能够完全并行运行的代码比例
N 表示可用的计算单元数(处理器或物理内核数)
如果一个算法中总任务的50%(p=0.5)可以并行执行,那么在具有两个物理内核的微处理器上的最大加速比为1.33,如一个带有1000份任务的算法,其中有500份并行任务,如果串行版本需要消耗1000秒,那么并行的话就是750秒
Gustafson 法则
Gustafson 法则是在固定的时间i内可以执行的工作量
总工作量(单元数)=s+(N*P)
其中
S表示一次执行完成的工作单元数
P表示每一部分能够完全并行执行的工作单元数
N表示可用的执行单元数(处理数或者物理内核数)
如有 50个单元的顺序执行和50是个可以并行的工作单元,你的微处理器是8核的
那么 总工作量(单元数)=50+(8*50)=450 单元的工作量
通过上面两个法则,我们就知道并行编程的重要性,下面我们用代码测试一下
class Program { static void Main(string[] args) { Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); Run1(); Run2(); stopwatch.Stop(); Console.WriteLine("串行执行所需要的时间{0}", stopwatch.ElapsedMilliseconds); stopwatch.Restart(); Parallel.Invoke(Run1,Run2); stopwatch.Stop(); Console.WriteLine("串行执行所需要的时间{0}", stopwatch.ElapsedMilliseconds); Console.ReadLine(); } static void Run1() { Thread.Sleep(5000); Console.WriteLine("任务一"); } static void Run2() { Console.WriteLine("任务二"); Thread.Sleep(5000); } }
结果
可想而知我们的时间就减少了一半,是不是很开心,下面我们对C# 提供给我们的类进行来解释一下
Parallel类
在这里我要说一下parallel 提供的是任务而不是线程,任务是架构在线程之上的,任务通过底层算法会根据你电脑的现在状况来选择cup核来为你工作
在Parallel下面有三个常用的方法invoke,for和forEach。
- Invoke 是执行并行方法
可以传递void返回值得函数
Parallel.Invoke(Run1,Run2);
也可以传递 lambda表达式,通过Parallel.Invoke 编写的并行执行的代码一定不能依赖于特定的执行顺序,如果需要以特定的执行顺序允许并发代码,后面章节中还会使用高级的东西
Parallel.Invoke(()=>{ Run1(); },Run2);
2.Parallel.For
这个函数对一下数据的检索和添加非常好,
class Program { static void Main(string[] args) { List<int> excel1=null; List<int> excel2=null; //并行读出两个表的而数据 Parallel.Invoke(() => { excel1 = GetExcel1(); }, () => { excel2 = GetExcel2();}); //通过并行方式快速将excel2中符合添加的数据加载到excel1表中 Parallel.For(0,excel2.Count,(i)=>{ if(excel2[i]%2==0) { excel1.Add(excel2[i]); } }); } static List<int> GetExcel1() { Thread.Sleep(5000); Console.WriteLine("任务一"); List<int> listExcel1 = new List<int>(); for (int i = 0; i < 100; i++) { listExcel1.Add(i); } return listExcel1; } static List<int> GetExcel2() { Thread.Sleep(5000); Console.WriteLine("任务二"); List<int> listExcel1 = new List<int>(); for (int i = 100; i < 1000; i++) { listExcel1.Add(i); } return listExcel1; } }
3. Parallel.ForEach
对应foreach是分片的,他的运用场合也挺多的,自己慢慢去理解吧
Parallel.ForEach(Partitioner.Create(0, 3000000), i => { Console.WriteLine("开始{0}-------结束{1}",i.Item1,i.Item2); });