cc

  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  38 随笔 :: 14 文章 :: 21 评论 :: 0 Trackbacks
Eric Bergman-Terrell 
.NET Remoting 使您可以跨多台计算机轻松进行分布计算,只需完成非常少的编程工作。在本文中,Eric Bergman-Terrell 创建了一个名为 Digits of Pi 的应用程序,它使用并行的多台计算机以不可思议的精度计算 p 值。他设法在 12 小时内完成了 10,000 位数的计算,却只使用了相当少的计算资源。这比用一台计算机单独完成计算快了 300%。

单击下载文件下载示例应用程序源代码后,打开 Everything.sln 解决方案。此解决方案包含运行“Digits of Pi”应用程序所需的三个项目(Client、Server 和 ServerLoader)。还包含一个名为 SimpleClient 的项目,我们稍后再讨论它。加载 Everything.sln 之后,请选择 Build(编译)| Batch Build...(批编译...)。单击 Select All(全部选定)按钮,然后单击 Build(编译)。编译所有内容后,请在本地计算机以及您的 LAN 中的远程计算机上安装该软件。

在本地计算机上,创建一个文件夹并将以下文件复制到其中:

Server\bin\Release\Plouffe_Bellard.dll
Client\bin\Release\DigitsOfPi.exe

在每个远程计算机和本地计算机上,创建一个文件夹并将以下文件复制到其中:

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

然后运行 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 都用于计算 p 值。输入所有计算机名后,单击 OK(确定)。

然后指定要计算的位数(参见图 2)并单击 Calculate(计算)。请从较少的位数开始,p 值小数点后面的位数越多,程序所需的时间就越长。

图 3 显示了 Digits of Pi 程序如何在本地计算机和远程计算机中分配工作量,它使用 TCP/IP 端口 9000 发送请求并接收结果。接下来,我们将详细探讨 Remoting、Plouffe_Bellard 服务器对象、ServerLoader 程序、SimpleClient 程序和 Digits of Pi 程序。

Remoting 基础
.NET Remoting 使对象可以与其他对象通信,无论它们运行在同一台计算机上还是运行在远程计算机上。.NET Remoting 与 Web 服务非常类似,但是 .NET Remoting 技术更适于 Digits of Pi 这种完全以 .NET 编程语言编写的应用程序,并且只能在运行 .NET Framework 的计算机上运行。请参阅本文末尾“其他资源”中的“ASP.NET Web Services or .NET Remoting: How to Choose”,对两种技术进行比较。 

您可以通过以下步骤使用 .NET Remoting 访问远程对象:

创建从 System.MarshalByRefObject 继承的 .NET 服务器对象 (DLL)。该服务器对象将在远程计算机和本地计算机上运行。 
创建通过调用 RemotingConfiguration.Configure 加载服务器对象的服务器加载器程序。服务器加载器程序也将在远程计算机和本地计算机上运行。 
创建使用 Activator.GetObject 访问服务器对象的客户端程序。您需要添加对服务器对象的引用以编译此程序。此客户端程序只在本地计算机上运行。 
服务器对象
服务器对象将计算指定的九位 p 值。它被命名为 Plouffe_Bellard,因为它使用 Fabrice Bellard 的增强的 Simon Plouffe 算法。虽然存在更快的算法,但 Plouffe-Bellard 算法非常简单(少于 300 行源代码),它使用少量的内存,并且由于九位数字可以单独计算,因此更适于并行执行。Plouffe_Bellard.CalculatePiDigits 方法将计算在指定位置开始的九位 p 值。例如,CalculatePiDigits(1) 从第一位开始返回九位数字:141592653。CalculatePiDigits(10) 从第十位开始返回九位数字,依此类推。 

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(计算)按钮开始计算第一个九位 p 值。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 仅通过访问远程计算机上的服务器对象来计算前九位 p 值。而 Digits of Pi 则同时使用 Configure(配置)对话框中指定的远程计算机和本地计算机(如图 1 所示)并行计算用户指定的小数位。服务器对象在单独的线程中访问,以便在可能需要很长时间的计算过程中保持 Digits of Pi GUI 对用户操作的响应性。 

Digits of Pi 使用数组将作业分为九位数据块,将工作量分配到所有可用的计算机上。用户单击 Calculate(计算)按钮后,将创建 SolutionArray(参见图 4)。SolutionArray 为要计算的每组九位 p 值分配一个 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 调用,并显示 p 的值。

表 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;
}

每个线程都使用相同的算法:如果有更多的工作要处理,线程将夺取下一个 SolutionItem,在 SolutionItem 中存储服务器对象的计算机名,计算指定的九位小数,并将结果存储在 SolutionItem 中。此进程将一直运行,直到所有 SolutionItem 中都填充了结果。有关详细信息,请参见表 4。

表 4:CalculationThread.Calculate。

public void Calculate()
{
  Plouffe_Bellard PiCalculator = 
    RemotePiCalculator.GetPiCalculator(
      GetRealMachineName(machineName));

  if (PiCalculator != null)
  {
    SolutionItem Item = null;
    bool Abort;

    do
    {
      Abort = solutionArray.Abort;

      if (!Abort)
      {
        Item = solutionArray.GetNextItem();

        if (Item != null)
        {
          Item.MachineName = machineName;

          try
          {
            Item.Results = 
           PiCalculator.CalculatePiDigits(Item.Digit);
          }
          catch (Exception e)
          {
            Abort = true;
            MessageBox.Show(
              "无法访问主机上的远程对象 " +
              machineName + Environment.NewLine + 
              Environment.NewLine + "Message:  " + 
              e.Message, Globals.ProgramName, 
              MessageBoxButtons.OK, 
              MessageBoxIcon.Error);
          }

          UpdateStatisticsDelegate USD = new 
            UpdateStatisticsDelegate(
              MF.UpdateStatistics);

          MF.Invoke(USD, new Object[] {} ;
        }
      }
    } while (Item != null && !Abort);

    calculationDone.Set();
  }
}

下面是逐步的说明:

GetRealMachineName 从多 CPU 计算机名中删除 @1 模式。例如,GetRealMachineName("Brainiac@1" 返回 "Brainiac"。有关多 CPU 计算机名的解释,请参见图 1 对话框中的文本。 
知道正确的计算机名后,将其传递给 RemotePiCalculator.GetPiCalculator,这样才可以通过 PiCalculator 变量访问该计算机上的服务器对象。 
如果用户单击了 Cancel(取消)按钮,将设置 Abort 属性。如果 Abort 属性为 true,线程将停止计算。 
对 MF.Invoke 的调用使线程可以安全地更新 ListView 中的统计数据(参见图 2),即使该 ListView 是由另一个线程创建的。在 32 位 Windows 编程中,绝不允许在创建某个控件的线程之外处理该控件。 
完成循环(即计算完指定的所有 p 位数或者用户单击 Cancel [取消] 按钮)后,将调用线程的 AutoResetEvent 的 Set 函数。 
当每个线程都调用其 AutoResetEvent 的 Set 函数后,将返回对 WaitHandle.WaitAll 的调用并显示结果。 
线程同步
如果 Digits of Pi 的代码由多个线程同时访问,可能会有多个地方出现错误。例如,如果两个线程同时调用 SolutionArray.GetNextItem,可能会返回相同的内容。这就是在 GetNextItem 方法中设置 [MethodImpl(MethodImplOptions.Synchronized)] 属性的原因,该属性可以确保一次只有一个线程调用该方法。如果方法的每一行代码都不应由多个线程同时访问,则使方法同步是一个很好的策略。 

由于 MainForm.Calculate 方法只有一行代码不能同时被多个线程访问,因此它将在该行代码之前调用 Monitor.Enter,并在其后调用 Monitor.Exit。如果该行代码已在其他线程上运行,Monitor.Enter 将被阻止。如果整个函数已实现同步,那么只保护需要防止多个线程访问的代码行可以提高性能。

从 System.Windows.Forms.Control 衍生的对象(例如 Button、TextBoxe、RichTextBoxe、Label、ListBoxe、ListView 等等)只应由创建它们的线程处理。要从非创建线程中安全处理 Control 衍生对象,请首先将处理代码放入一个方法,然后为该方法声明一个代理:

delegate void SetResultsTextDelegate(String Text);

private void SetResultsText(String Text)
{
  ResultsRichTextBox.Text = Text;
}

然后使用 Form.Invoke 间接调用该方法:

SetResultsTextDelegate SRTD = new 
   SetResultsTextDelegate(SetResultsText);

Invoke(SRTD, new object[] { "" } ;

Invoke 方法将从创建它的线程中调用该方法,它使用的参数与对象数组中的元素相对应。

小结
.NET Remoting 是一种在远程(和本地)计算机上执行代码的简单而有效的机制。只需将代码封装到 .NET 对象中,编写加载该对象并侦听请求的程序,然后在客户端程序中调用 Activator.GetObject。如果您的 LAN 中有一些闲置的计算机,可以利用它们轻松地解决并行问题。只需记住要使用正确的线程同步机制,以防止线程之间发生冲突。 

下载 TERRELL.ZIP

其他资源
“ASP.NET Web 服务还是 .NET Remoting:如何选择 ”(::URL::http://www.microsoft.com/china/msdn/library/dnbda/html/bdadotnetarch16.asp)  一文很有用,它对 .NET Web Service 和 .NET Remoting 进行了比较。 
Fabrice Bellard's Pi Page (::URL::http://fabrice.bellard.free.fr/pi/)  提供了一些用于计算 p 值的有用公式和源代码,包括 Digits of Pi 程序中使用的算法的 C 语言源代码。 
有关远程访问程序的源代码,请访问 www.personalmicrocosms.com/html/ra.html。此程序使用 .NET Remoting 显示远程计算机的桌面,并使用本地计算机的键盘和鼠标运行远程计算机。 
有关数学化方面的内容,请参阅 Petr Beckmann 著的《History of Pi》(St. Martin's Press 1971 年出版),这是一本相当不错的书,因为 p 的历史就是数学历史的微观反映。Beckmann 的书涵盖了 p 的数学历史以及政治历史。 
Ingo Rammer 的《Advanced .NET Remoting》(Apress 2002 年出版)是有关 Remoting 的权威指南。此书看起来更适合从头到尾的详细阅读。我倒是希望此书能够适合我的“随便翻翻”的阅读习惯。 
有关 Hardcore Visual Studio .NET 和 Pinnacle Publishing 的详细信息,请访问它们的 Web 站点 ::URL::http://www.pinpub.com/。

注意:这不是 Microsoft Corporation 的 Web 站点。Microsoft 对该站点的内容不承担责任。

本文转载自 2003 年 4 月份的 Hardcore Visual Studio .NET。版权所有 2003 Pinnacle Publishing, Inc.(除非另行说明)。保留所有权利。Hardcore Visual Studio .NET 是 Pinnacle Publishing, Inc. 独立发行的刊物。未经 Pinnacle Publishing, Inc. 事先同意,不得以任何形式使用或复制本文的任何部分(评论文章中的简短引用除外)。如需与 Pinnacle Publishing, Inc.联系,请致电 1-800-788-1900。
posted on 2006-12-07 15:02 醒目西西 阅读(1418) 评论(9)  编辑 收藏 引用 所属分类: 编程相关

评论

# re: 使用 .NET Remoting 实现并行计算 [转] 2010-07-09 12:22 ReynaMARSH20
This seems to be very feasible to order thesis samples just about this good post in the <a href="http://www.exclusivethesis.com">thesis writing</a> service peculiarly when scholars do not have time.   回复  更多评论
  

# re: 使用 .NET Remoting 实现并行计算 [转] 2010-10-07 14:08 essay service
Good post. But how to anticipate comment spamming? Because essays help could fail your degree.  回复  更多评论
  

# re: 使用 .NET Remoting 实现并行计算 [转] 2013-08-22 18:12 this link
Check out Essays Review company whenever you need to glance over informative college paper writing service reviews.  回复  更多评论
  

# re: 使用 .NET Remoting 实现并行计算 [转] 2013-08-25 17:55 custom essay writing services reviews
Don’t have the faintest idea which firm to select to get assistance from? Go over QualityEssay testimonials, and make a right decision.  回复  更多评论
  

# re: 使用 .NET Remoting 实现并行计算 [转] 2013-08-25 20:49 EssaysService rewiew
Don’t have the faintest idea which firm to pick to get assistance from? Look through PremiumQualityEssays testimonials "best-writing-services.com", and arrive at a good decision.  回复  更多评论
  


只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理