并行计算两个矩阵
要求:
编写一个WPF应用程序,利用数据并行计算两个矩阵(M×N和N×P)的乘积,得到一个M×P的矩阵。
(1)在代码中用多任务通过调用某方法实现矩阵并行运算,在调用的参数中分别传递M、N、P的大小。
(2)程序中至少要测试3次有代表性的不同大小的矩阵运算,并显示其并行运行用时。
1.初始化矩阵,用100以内的随机数填充
private double[,] Init(int row, int col)
{
double[,] data = new double[row, col];
Random r = new Random();
for(int i = 0; i < row; i++)
{
for(int j = 0; j < col; j++)
{
data[i, j] = r.Next(100);
}
}
return data;
}
2.串行算法
private void Compute(double[,] a, double[,] b, double[,] result)
{
int aRows = a.GetLength(0);
int aCols = a.GetLength(1);
int bCols = b.GetLength(1);
for(int i = 0;i < aRows; i++)
{
for (int j = 0; j < bCols; j++)
{
double temp = 0;
for (int k = 0; k < aCols; k++)
{
temp += a[i, k] * b[k, j];
}
result[i, j] = temp;
}
}
}
3.并行算法,仅将最外层换为Parallel.For
private void ParallelCompute(double[,] a, double[,] b, double[,] result)
{
int aRows = a.GetLength(0);
int aCols = a.GetLength(1);
int bCols = b.GetLength(1);
Action<int> action = (i) =>
{
for (int j = 0; j < bCols; j++)
{
double temp = 0;
for (int k = 0; k < aCols; k++)
{
temp += a[i, k] * b[k, j];
}
result[i, j] = temp;
}
};
Parallel.For(0, aRows, action);
}
4.定义时钟,并为防止运行时界面卡顿使用异步编程
Stopwatch stopwatch = new Stopwatch();
public MainWindow()
{
InitializeComponent();
}
private async void button_Click(object sender, RoutedEventArgs e)
{
textblock.Text = "";
long[] t1 = await Task.Run(() => Multiply(325,18,66));
textblock.Text = string.Format("测试1(矩阵1:325×18,矩阵2:18×66),非并行用时:{0}毫秒,并行用时:{1}毫秒", t1[0], t1[1]);
long[] t2 = await Task.Run(() => Multiply(3250, 180, 660));
textblock.Text += string.Format("\n测试2(矩阵2:3250×180,矩阵2:180×660),非并行用时:{0}毫秒,并行用时:{1}毫秒", t2[0], t2[1]);
long[] t3 = await Task.Run(() => Multiply(32500, 200, 900));
textblock.Text += string.Format("\n测试3(矩阵3:32500×200,矩阵2:200×900),非并行用时:{0}毫秒,并行用时:{1}毫秒", t3[0], t3[1]);
}
5.初始化矩阵后计算,同时计时,结束后返回时钟数组
private long[] Multiply(int m, int n, int p)
{
long[] timeElapsed = new long[2];
double[,] m1 = Init(m, n);
double[,] m2 = Init(n, p);
double[,] result = new double[m, p];
//串行
stopwatch.Restart();
result = new double[m, p];
Compute(m1, m2, result);
stopwatch.Stop();
timeElapsed[0] = stopwatch.ElapsedMilliseconds;
//并行
stopwatch.Restart();
result = new double[m, p];
ParallelCompute(m1, m2, result);
stopwatch.Stop();
timeElapsed[1] = stopwatch.ElapsedMilliseconds;
return timeElapsed;
}
结果:
问题讨论:
1.结果只出现一行,没有用+=。输出未换行,字符串添加\n。
2.初始化时,System.IndexOutOfRangeException:“索引超出了数组界限。”原因:i,j出现写反的错误。
3.仅将最外层的for改为Parallel.For更优。
4.出现数过大,等待时间过久的问题