发新话题
打印

使用.NET Remoting实现并行计算

使用.NET Remoting实现并行计算

  [简介]
过去,做一个并行计算的试验要费九牛二虎之力,今天,有了.NET Remoting,我们只需要完成非常少的编程工作,便可以跨多台计算机轻松进行分布计算。在本文中,Eric Bergman-Terrell创建了一个名为Digits of Pi的应用程序,它使用并行的多台计算机以不可思议的精度计算π值。他设法在12小时内完成了10,000位数的计算,却只使用了相当少的计算资源。这比用一台计算机单独完成计算快了300%。

欢迎进入.NET Remoting的奇妙世界!在这篇文章里,您将与我一起,亲自动手体验并行计算的威力。为了方便您更好地理解这篇文章,请首先按照下面的步骤作一番准备:
1.从附增光盘获取示例应用程序及源代码。
2.打开Everything.sln解决方案。此解决方案包含运行“Digits of Pi”应用程序所需的三个项目(Client、Server和ServerLoader)。还包含一个名为SimpleClient的项目。加载Everything.sln之后,请选择Build(编译)| Batch Build...(批编译...)。单击Select All(全部选定)按钮,然后单击Build(编译)。编译所有内容后,请在本地计算机以及您的LAN中的远程计算机上安装该软件。
3.在本地计算机上,创建一个文件夹并将以下文件复制到其中:
Server\bin\Release\Plouffe_Bellard.dll
Client\bin\Release\DigitsOfPi.exe
4.在每个远程计算机和本地计算机上,创建一个文件夹并将以下文件复制到其中:

Server\bin\Release\Plouffe_Bellard.dll
ServerLoader\bin\Release\ServerLoader.exe
ServerLoader\ServerLoader.exe.config

5.然后运行ServerLoader.exe程序。当然,运行ServerLoader和Digits of Pi程序之前,需要在每台计算机上安装.NET Framework。

在所有远程计算机和本地计算机上运行ServerLoader程序后,请运行Digits of Pi程序。单击Configure...(配置...)(参见图1),添加本地计算机名和远程计算机名。如果不确定某台计算机的名称,请查看ServerLoader程序,它在表中显示其计算机名。如果您很幸运地拥有一个多CPU系统,您只需为所有CPU输入一次计算机名。只需在计算机名后键入@符号和一个编号。例如,如果您拥有一个名为“Brainiac”的双CPU系统,则键入以下计算机名:“Brainiac@1”和“Brainiac@2”。为多CPU系统输入多个计算机名可以确保所有计算机的CPU都用于计算π值。输入所有计算机名后,单击OK(确定)。
指定要计算的位数(参见图2)并单击Calculate(计算)。请从较少的位数开始,π值小数点后面的位数越多,程序所需的时间就越长。
图3显示了Digits of Pi程序如何在本地计算机和远程计算机中分配工作量,它使用TCP/IP端口9000发送请求并接收结果。接下来,我们将详细探讨Remoting、Plouffe_Bellard服务器对象、ServerLoader程序、SimpleClient程序和Digits of Pi程序。

服务器对象
服务器对象将计算指定的九位π值。它被命名为Plouffe_Bellard,因为它使用Fabrice Bellard的增强Simon Plouffe算法。虽然存在更快的算法,但Plouffe-Bellard算法非常简单(少于300行源代码),它使用少量的内存,并且由于九位数字可以单独计算,因此更适于并行执行。Plouffe_Bellard.CalculatePiDigits方法将计算在指定位置开始的九位π值。例如,CalculatePiDigits(0)从第一位开始返回九位数字:141592653。CalculatePiDigits(9)从第十位开始返回九位数字,依此类推。

ServerLoader
ServerLoader程序将加载服务器对象,指定通过LAN访问服务器对象的协议和端口,侦听来自客户端程序的传入调用,处理调用并返回结果。特别值得注意的是,所有这些只需一行代码便可完成,只需通过使用配置文件的路径调用RemotingConfiguration.Configure方法。ServerLoader程序将加载名为ServerLoader.exe.config的配置文件(参见代码段1)。此配置文件指定以SingleCall模式加载服务器对象,即每个传入调用都由服务器对象的一个新实例处理。如果服务器对象以Singleton模式加载,每个传入调用都将由同一个实例处理。类型属性指定服务器对象的完整类型名称(包括PB命名空间)及其程序集的名称。objectUri属性指定对象的统一资源标识符(URI)的端点。<channel>元素指定使用TCP协议,端口9000访问服务器对象。
代码段1:ServerLoader.exe.config
<configuration>
<system.runtime.remoting>
<application name = "ServerLoader">
<service>
<wellknown
mode="SingleCall"
type="PB.Plouffe_Bellard,Plouffe_Bellard"
objectUri="Plouffe_Bellard"/>
</service>
<channels>
<channel ref="tcp server" port="9000"/>
</channels>
</application>
</system.runtime.remoting>
</configuration>
SimpleClient

我创建了一个名为SimpleClient的程序,以说明客户端程序访问远程计算机上的服务器对象是多么容易。要运行SimpleClient,首先在远程计算机上运行ServerLoader,然后在本地计算机上运行SimpleClient.exe程序。在Remote Machine(远程计算机)文本框中输入远程计算机的名称,然后单击Calculate(计算)按钮开始计算第一个九位π值。SimpleClient的CalculateButton_Click方法包含客户端访问远程服务器所需的所有代码(参见代码段2)。可以使用由远程计算机名、协议(TCP)和端口号(9000)组成的URL访问远程服务器。例如,要访问我的“Pentium 200”计算机,则URL为“tcp://Pentium 200:9000/ServerLoader/Plouffe_Bellard”。创建URL后,将使用服务器的类型(Plouffe_Bellard)和URL调用Activator.GetObject。然后,返回的值被转换为Plouffe_Bellard对象以备使用。调用其CalculatePiDigits方法时,请求被发送到远程计算机上的ServerLoader。然后,服务器对象计算小数位。最后,在一个文本框中显示返回客户端程序的结果。
代码段2:用于访问远程服务器的SimpleClient代码

private void CalculateButton_Click(object sender,System.EventArgs e)
{
Cursor.Current = Cursors.WaitCursor;
Plouffe_Bellard PiCalculator = null;
String MachineName = RemoteMachineTextBox.Text;
try
{
int port = 9000;
String URL = "tcp://"   MachineName   ":"   
port   "/ServerLoader/Plouffe_Bellard";
PiCalculator = (Plouffe_Bellard)
Activator.GetObject(typeof(Plouffe_Bellard), URL);
ResultsTextBox.Text = "3."   
PiCalculator.CalculatePiDigits(1);
}
catch(Exception)
{
MessageBox.Show(
"需要在计算机"   
MachineName,
"Simple Client上运行ServerLoader.exe",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
Cursor.Current = Cursors.Arrow;
}


Digits of Pi客户端
Digits of Pi客户端程序比SimpleClient更复杂。SimpleClient仅通过访问远程计算机上的服务器对象来计算前九位π值。而Digits of Pi则同时使用Configure(配置)对话框中指定的远程计算机和本地计算机(如图1所示)并行计算用户指定的小数位。服务器对象在单独的线程中访问,以便在可能需要很长时间的计算过程中保持Digits of Pi GUI对用户操作的响应性。
Digits of Pi使用数组将作业分为九位数据块,将工作量分配到所有可用的计算机上。用户单击Calculate(计算)按钮后,将创建SolutionArray(参见图4)。SolutionArray为要计算的每组九位π值分配一个SolutionItem元素。服务器对象计算m_Digit字段指定的九位数组后,数位将存储在m_Results成员中。m_MachineName成员包含运行服务器的计算机的名称。存储计算机名是为了使Digits of Pi能够显示每台计算机计算的小数总数(参见图2)。
为使服务器对象并行计算,Digits of Pi将为每个服务器对象创建一个线程并启动线程计算。然后,必须等待所有线程完成计算后才能显示最终结果。WaitHandle对于等待多个线程很有用。Digits of Pi将为每个线程使用一个WaitHandle,以等待所有线程完成计算。
将调用CalculationThread.Calculate(参见代码段3)以便为每个服务器对象创建一个线程。该操作将启动线程运行,然后返回一个AutoResetEvent(从WaitHandle衍生而来)。每个线程的AutoResetEvent都存储在一个数组中,然后数组被传递给WaitHandle.WaitAll。完成线程计算后,将对其AutoResetEvent调用Set方法。最后一个线程调用Set方法后,将返回WaitAll调用,并显示π的值。
代码段3:CalculationThread。
public static WaitHandle Calculate(
SolutionArray solutionArray, String machineName)
{
CalculationThread calculationThread = new
CalculationThread(solutionArray, machineName);
Thread thread = new Thread(new
ThreadStart(calculationThread.Calculate));
thread.Start();
return calculationThread.calculationDone;
}

每个线程都使用相同的算法:如果有更多的工作要处理,线程将夺取下一个So

TOP

发新话题