随着多核时代的到来,并行开发越来越展示出它的强大威力。在了解并行开发之前,我们先来了解两个法则“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);
});