29.4 数据并行
数据并行是指对集合或数组中的元素并行执行相同操作的情况。Parallel类中的For和ForEach方法及其重载版本支持使用强制性语法的数据并行。
//非并行版本
foreach(var item in sourceCollection)
{
Process(item);
}
//并行版本
Parallel.ForEach(sourceCollection,item=>Process(item));
当并行循环运行时,TPL将对数据源进行分区,以便循环能够同时对多个部分进行操作。在后台,任务计划程序将根据系统资源和工作负荷来对任务进行分区。如有可能,计划程序会在工作负荷变得不平衡的情况下在多个线程和处理器之间重新分配工作。
代码清单29-7 演示了Parallel.For的使用。
代码清单29-7 使用Parallel.For进行并计算示例
using System;
using System.Diagnostics;
using System.Threading.Tasks;
namespace ProgrammingCSharp4
{
class ParallelSample
{
//顺序循环,非并行计算
static void MultiplyMatricesSequential(double[,]matA,double[,]matB,
double[,]result)
{
int matACols=matA.GetLength(1);
int matBCols=matB.GetLength(1);
int matARows=matA.GetLength(0);
for(int i=0;i<matARows;i++)
{
for(int j=0;j<matBCols;j++)
{
for(int k=0;k<matACols;k++)
{
//matA数组按列循环乘以matB数组按行循环
result[i,j]+=matA[i,k]*matB[k,j];
}
}
}
}
///<summary>
///并行计算
///</summary>
///<param name="matA"></param>
///<param name="matB"></param>
///<param name="result"></param>
static void MultiplyMatricesParallel(double[,]matA,double[,]matB,
double[,]result)
{
int matACols=matA.GetLength(1);
int matBCols=matB.GetLength(1);
int matARows=matA.GetLength(0);
Parallel.For(0,matARows,i=>
{
for(int j=0;j<matBCols;j++)
{
double temp=0;
for(int k=0;k<matACols;k++)
{
temp+=matA[i,k]*matB[k,j];
}
result[i,j]=temp;
}
});
}
static void Main(string[]args)
{
int colCount=180;
int rowCount=2000;
int colCount2=270;
double[,]m1=InitializeMatrix(rowCount,colCount);
double[,]m2=InitializeMatrix(colCount,colCount2);
double[,]result=new double[rowCount,colCount2];
Console.WriteLine(“执行顺序循环……”);
Stopwatch stopwatch=new Stopwatch();
stopwatch.Start();
MultiplyMatricesSequential(m1,m2,result);
stopwatch.Stop();
Console.WriteLine(“顺序循环执行结束,所花时间:{0}”,
stopwatch.ElapsedMilliseconds);
//询问用户是否输出计算结果
OfferToPrint(rowCount,colCount2,result);
//重置计时器
stopwatch.Reset();
//重置result变量
result=new double[rowCount,colCount2];
Console.WriteLine();
//执行并行循环
Console.WriteLine(“执行并行计算中……”);
stopwatch.Start();
MultiplyMatricesParallel(m1,m2,result);
stopwatch.Stop();
Console.WriteLine(“并行循环执行结束,所花时间:{0}”,
stopwatch.ElapsedMilliseconds);
OfferToPrint(rowCount,colCount2,result);
Console.WriteLine();
Console.WriteLine(“单击任意键退出……”);
Console.ReadKey();
}
///<summary>
///使用行列数初始化矩形数组
///</summary>
///<param name="rows">行数</param>
///<param name="cols">列数</param>
///<returns>初始化好的矩形数组实例</returns>
static double[,]InitializeMatrix(int rows,int cols)
{
double[,]matrix=new double[rows,cols];
Random r=new Random();
for(int i=0;i<rows;i++)
{
for(int j=0;j<cols;j++)
{
//使用随机数初始化矩形数组
matrix[i,j]=r.Next(100);
}
}
return matrix;
}
///<summary>
///询问用户是否显示计算结果
///</summary>
///<param name="rowCount">行数</param>
///<param name="colCount">列数</param>
///<param name="matrix">计算结果</param>
private static void OfferToPrint(int rowCount,int colCount,double[,]matrix)
{
Console.WriteLine(“计算结束,显示结果吗(y/n)”);
char c=Console.ReadKey().KeyChar;
if(c=='y'||c=='Y')
{
Console.WindowWidth=150;
Console.WindowHeight=30;
Console.WriteLine();
for(int x=0;x<rowCount;x++)
{
if(x>0&&x%2==0)
{
Console.WriteLine(“按任意键继续……”);
Console.ReadKey();
}
Console.WriteLine(“行{0}:”,x);
for(int y=0;y<colCount;y++)
{
Console.Write("{0:#.##}",matrix[x,y]);
}
Console.WriteLine();
}
}
}
}
}
上述代码的运行结果为:
执行顺序循环……
顺序循环执行结束,所花时间:3486
计算结束,显示结果吗(y/n)
n
执行并行计算中……
并行循环执行结束,所花时间:1752
计算结束,显示结果吗(y/n)
n
单击任意键退出……