一、实验要求
编写一个WPF应用程序,利用数据并行计算两个矩阵(M×N和N×P)的乘积,得到一个M×P的矩阵。
具体要求
(1)在代码中用多任务通过调用某方法实现矩阵并行运算,在调用的参数中分别传递M、N、P的大小。
(2)程序中至少要测试3次有代表性的不同大小的矩阵运算,并显示其并行运行用时。
二、实验结果展示
三、实验代码展示
1.xml部分
<Window x:Class="实验报告3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:实验报告3"
mc:Ignorable="d"
Title="利用Parallel.For实现矩阵相乘" Height="450" Width="894">
<Grid Background="AliceBlue">
<DockPanel>
<StackPanel DockPanel.Dock="Top">
<Border BorderThickness="5" Margin="2" BorderBrush="Red" VerticalAlignment="Center">
<TextBlock Text="利用数据并行计算两个矩阵(M*N和N*P)的乘积" FontSize="25" FontFamily="微软雅黑" HorizontalAlignment="Center"/>
</Border>
</StackPanel>
<ScrollViewer DockPanel.Dock="Top" Height="335">
<DockPanel>
<StackPanel DockPanel.Dock="Left" Width="105" VerticalAlignment="Center">
<Label Content="M值:" Width="60" FontSize="18" Background="AliceBlue" Margin="10"/>
<Label Content="N值:" Width="60" FontSize="18" Background="AliceBlue" Margin="10"/>
<Label Content="P值:" Width="60" FontSize="18" Background="AliceBlue" Margin="10"/>
</StackPanel>
<StackPanel DockPanel.Dock="Left" Width="200" VerticalAlignment="Center">
<Border BorderThickness="5" Margin="2" BorderBrush="Orange">
<TextBox x:Name="t1" Text="" FontSize="18" Margin="1"/>
</Border>
<Border BorderThickness="5" Margin="2" BorderBrush="Orange">
<TextBox x:Name="t2" Text="" FontSize="18" Margin="1"/>
</Border>
<Border BorderThickness="5" Margin="2" BorderBrush="Orange">
<TextBox x:Name="t3" Text="" FontSize="18" Margin="1"/>
</Border>
</StackPanel>
<StackPanel DockPanel.Dock="Right">
<TextBlock x:Name="t4" Text="结果显示:" FontSize="18" FontFamily="楷体" Background="Black" Foreground="AliceBlue" Height="331" Width="534"/>
</StackPanel>
</DockPanel>
</ScrollViewer>
<Border DockPanel.Dock="Bottom" HorizontalAlignment="Center">
<Button Content="运行" Width="70" Height="30" Background="BlueViolet" Click="Button_Click"/>
</Border>
</DockPanel>
</Grid>
</Window>
2.cs部分
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace 实验报告3
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
//实验次数
int x = 0;
public MainWindow()
{
InitializeComponent();
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
//接收M,N,P
int aRow, aCol, bCol;
int.TryParse(t1.Text, out aRow);
int.TryParse(t2.Text, out aCol);
int.TryParse(t3.Text, out bCol);
//形成要用的两个矩阵ab ,里面存储的数是double类型的,当然在额外创建一个矩阵c接收结果
double[,] a, b, c;
a = initMatrix(aRow, aCol);
b = initMatrix(aCol, bCol);
c = new double[aRow, bCol];
//进行矩阵并行运算,并计算时间
long time1 = await Task.Run(() => timeSpan(a, b, c));
//将实验次数++
x++;
//将计算的值在右侧黑色文本框中显示出来
t4.Text += string.Format("\n测试{0}(矩阵1:{1}*{2},矩阵2:{3}*{4}),用时:{5}毫秒", x, aRow, aCol, aCol, bCol, time1);
}
//初始化矩阵
public double[,] initMatrix(int row, int column)
{
Random random= new Random();
double[,] matrix = new double[row,column];
for (int i = 0; i < row; i++)
{
for (int j = 0; j < column; j++)
{
matrix[i,j] = random.Next(100);
}
}
return matrix;
}
//并行矩阵乘法
public void ParallelMatrixMultiplication(double[,] a, double[,] b, double[,] c)
{
//获取两个矩阵的行列数,因为TryParse好像用不到全局变量里面,所以只能写的这么复杂了
int aRows = a.GetLength(0);
int aCols = a.GetLength(1);
int bCols = b.GetLength(1);
//计算并输出,但是 数太大 会产生 数组越界异常
// i是a行,j是b列,k是a列b行
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];
}
c[i, j] = temp;
}
};
//action只是定义了一个方法,所以是不是自动运行的,真正运行的代码是下面这行 并行运行代码,这也解释了i的取值是多少的问题
Parallel.For(0, aRows , action);
}
//计算运算时间
public long timeSpan(double[,] a, double[,] b, double[,]c)
{
Stopwatch sw = Stopwatch.StartNew();
ParallelMatrixMultiplication(a, b, c);
sw.Stop();
return sw.ElapsedMilliseconds;
}
}
}
四、实验总结
1. 为什么要用panel控件(各种panel控件),明明用了跟没用一样。
答: 简单的说,panel控件是一个容器控件,你可以在上面放置别的控件,当做一个Form用。应用程序会尽可能将一个面板中的所有控件分页到同一屏幕上。通过将控件分组到 Panel 控件中, 应用程序还可使用单个命令隐藏或显示一组控件。
当移动 Panel 控件时,它包含的所有控件也将移动
2. 所以Form是什么意思?
简单来讲就是Windows窗体应用,创建wpf自动生成的xml界面,也可以独立添加新的。官方一点来说就是:
1.窗体也是对象,窗体类定义了生成窗体的模板,每当实例化一个窗体类,就产生一个窗体2.Form类是所有窗体类的基类。
3.在一个项目中,每个窗体都有自己的Form.cs代码,但所有窗体只有一个启动窗体,核心便是 Program.cs文件里的Main()函数作为程序的主入口点。
3. textbox和textblock的区别
前者可以编辑,后者不可以。4. task.Run 其实在读程序时,可以直接读成“运行.....”
5.与界面交互,例如:将结果在界面中显示出来
6. cts = new System.Threading.CancellationTokenSource();
放在task(任务,cts.token) 用于侦听取消通知7. 可以直接用int.TryParse(a,out b); 接收文本框中的值
8. Action本身是一种方法,后面必须加分号.
Action<>是没有返回值,而有没有参数取决于<>有没有值类型,如有int,就是含有一个int型的参数,这时候就可以像for循环里面 int i=0; 随便使用 i 这个参数了。文章来源:https://www.toymoban.com/news/detail-451501.html9.本次实验有个小问题,就是结果数组写错了,写成了a列b列了,一直导致数组越界异常,耽误了两个多小时。。。。。文章来源地址https://www.toymoban.com/news/detail-451501.html
五、书上原码展示
1.xml部分
<Window x:Class="Experiment3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="利用Parallel.For实现矩阵相乘" Height="350" Width="525">
<DockPanel>
<Border DockPanel.Dock="Bottom" Background="Beige" Padding="0 5 0 5">
<Button Name="btnStart" Padding="20 0 20 0" HorizontalAlignment="Center" Content="开始" Click="btnStart_Click"/>
</Border>
<ScrollViewer>
<StackPanel Background="White" TextBlock.LineHeight="30">
<TextBlock Name="textBlock1" Margin="0 10 0 0" TextWrapping="Wrap"/>
</StackPanel>
</ScrollViewer>
</DockPanel>
</Window>
2.cs部分
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Experiment3
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
Stopwatch stopwatch = new Stopwatch();
public MainWindow()
{
InitializeComponent();
}
private async void btnStart_Click(object sender, RoutedEventArgs e)
{
long[] t1 = await Task.Run(() => Multiply(200, 18, 27));
textBlock1.Text = string.Format("测试1(矩阵1:200×18,矩阵2:18×27),用时:{1}毫秒", t1[0], t1[1]);
long[] t2 = await Task.Run(() => Multiply(2000, 180, 270));
textBlock1.Text += string.Format("\n测试2(矩阵1:2000×180,矩阵2:180×270),用时:{1}毫秒", t2[0], t2[1]);
long[] t3 = await Task.Run(() => Multiply(3000, 200, 300));
textBlock1.Text += string.Format("\n测试3(矩阵1:2000×200,矩阵2:200×300),用时:{1}毫秒", t3[0], t3[1]);
}
private long[] Multiply(int rowCount, int colCount, int colCount2)//参数分别是M,N,P
{
long[] timeElapsed = new long[2];
//初始化两个矩阵
double[,] m1 = InitializeMatrix(rowCount, colCount);
double[,] m2 = InitializeMatrix(colCount, colCount2);
//乘之后得到的矩阵,这里相当于手动取得
double[,] result = new double[rowCount, colCount2];
// 并行,
//计时开始
stopwatch.Restart();
result = new double[rowCount, colCount2];//M*P
MultiplyMatricesParallel(m1, m2, result);
//计时结束
stopwatch.Stop();
//返回时间
timeElapsed[1] = stopwatch.ElapsedMilliseconds;
return timeElapsed;
}
#region 并行
/// <summary>
/// 计算两个矩阵的乘积
/// </summary>
/// <param name="a">矩阵a</param>
/// <param name="b">矩阵b</param>
/// <param name="result">相乘的结果</param>
public static void MultiplyMatricesParallel(double[,] a, double[,] b, double[,] result)
{
//如果是64位机,将int改为Int64可提高性能,但修改后将无法在32位机器上运行
int aRows = a.GetLength(0);//a的行
int aCols = a.GetLength(1);//a的列,b的行
int bCols = b.GetLength(1);//b的列
// 内循环不需要并行
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);//实际上就是矩阵a每行都单独去运算,最后结果汇总,上面action中的i就是a的行arows,比如第一行去跟b的j列运算,同时第二(i)行野区和b的j列运算
}
#endregion
public 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;
}
}
}
到了这里,关于网络应用编程 实验3 矩阵并行计算练习实验的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!