【簡介】 過去,做一個并行計算的試驗要費九牛二虎之力,今天,有了.NET Remoting,我們只需要完成非常少的編程工作,便可以跨多臺計算機輕松進行分布計算。在本文中,Eric Bergman-Terrell創建了一個名為Digits of Pi的應用程序,它使用并行的多臺計算機以不可思議的精度計算π值。他設法在12小時內完成了10,000位數的計算,卻只使用了相當少的計算資源。這比用一臺計算機單獨完成計算快了300%! | ||||
歡迎進入.NET Remoting的奇妙世界!在這篇文章里,您將與我一起,親自動手體驗并行計算的威力。為了方便您更好地理解這篇文章,請首先按照下面的步驟作一番準備:
| ||||
在所有遠程計算機和本地計算機上運行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
| ||||
SimpleClient | ||||
我創建了一個名為SimpleClient的程序,以說明客戶端程序訪問遠程計算機上的服務器對象是多么容易。要運行SimpleClient,首先在遠程計算機上運行ServerLoader,然后在本地計算機上運行SimpleClient.exe程序。在Remote Machine(遠程計算機)文本框中輸入遠程計算機的名稱,然后單擊Calculate(計算)按鈕開始計算第一個九位π值。SimpleClient的CalculateButton_Click方法包含客戶端訪問遠程服務器所需的所有代碼(參見代碼段2)?梢允褂糜蛇h程計算機名、協議(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代碼
| ||||
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。
| ||||
每個線程都使用相同的算法:如果有更多的工作要處理,線程將奪取下一個SolutionItem,在SolutionItem中存儲服務器對象的計算機名,計算指定的九位小數,并將結果存儲在SolutionItem中。此進程將一直運行,直到所有SolutionItem中都填充了結果。有關詳細信息,請參見代碼段4。代碼段4:CalculationThread.Calculate
| ||||
下面是每一步的說明:
| ||||
線程同步 | ||||
如果Digits of Pi的代碼由多個線程同時訪問,可能會有多個地方出現錯誤。例如,如果兩個線程同時調用SolutionArray.GetNextItem,可能會返回相同的內容。這就是在GetNextItem方法中設置[MethodImpl(MethodImplOptions.Synchronized)]屬性的原因,該屬性可以確保一次只有一個線程調用該方法。如果方法的每一行代碼都不應由多個線程同時訪問,則使方法同步是一個很好的策略。 | ||||
由于MainForm.Calculate方法只有一行代碼不能同時被多個線程訪問,因此它將在該行代碼之前調用Monitor.Enter,并在其后調用Monitor.Exit。如果該行代碼已在其他線程上運行,Monitor.Enter將被阻止。如果整個函數已實現同步,那么只保護需要防止多個線程訪問的代碼行就可以提高性能。 | ||||
從System.Windows.Forms.Control派生的對象(例如Button、TextBox、RichTextBox、Label、ListBox、ListView等等)只應由創建它們的線程處理。要從非創建線程中安全處理Control衍生對象,請首先將處理代碼放入一個方法,然后為該方法聲明一個代理:
| ||||
然后使用Form.Invoke間接調用該方法:
| ||||
Invoke方法將從創建它的線程中調用該方法,它使用的參數與對象數組中的元素相對應。 | ||||
小結 | ||||
.NET Remoting是一種在遠程(和本地)計算機上執行代碼簡單有效的機制。只需將代碼封裝到.NET對象中,編寫加載該對象并偵聽請求的程序,然后在客戶端程序中調用Activator.GetObject。如果您的LAN中有一些閑置的計算機,可以利用它們輕松地解決并行問題。只需記住要使用正確的線程同步機制,以防止線程之間發生沖突。 |
文章來源于領測軟件測試網 http://www.kjueaiud.com/