Remoting之非同步操作模式
在Remoting中,我們可以使用以下幾種非同步的方式:
1、普通非同步
2、回撥非同步
3、單向非同步
一個一個來說,首先我們這麼修改我們的遠端物件:
{
Console.WriteLine("非同步方法開始");
System.Threading.Thread.Sleep(time);
Console.WriteLine("非同步方法結束");
return a+b;
}
這個方法傳入2個引數,返回2個引數和表示方法執行成功,方法需要time毫秒的執行時間,這是一個長時間的方法。
如果方法我們通過非同步遠端呼叫,這裡需要注意到這個方法輸出的行是在伺服器端輸出的而不是客戶端。因此,為了測試簡單,我們還是在採用本地物件,在實現非同步前我們先來看看同步的呼叫方法,為什麼說這是一種阻塞?因為我們呼叫了方法主執行緒就在等待了,看看測試:
RemoteObject.MyObject app=new RemoteObject.MyObject();
Console.WriteLine(app.ALongTimeMethod(1,2,1000));
Method();
Console.WriteLine("用了"+((TimeSpan)(DateTime.Now-dt)).TotalSeconds+"秒");
Console.ReadLine();
假設method方法是主執行緒的方法,需要3秒的時間:
{
Console.WriteLine("主執行緒方法開始");
System.Threading.Thread.Sleep(3000);
Console.WriteLine("主執行緒方法結束");
}
好了,現在開始執行程式:
用了4秒,說明在我們的方法開始以後本地就一直在等待了,總共用去的時間=本地方法+遠端方法,對於長時間方法呼叫這顯然不科學!我們需要改進:
1、普通非同步:
首先在main方法前面加上委託,簽名和返回型別和非同步方法一致。
main方法裡面這麼寫:
RemoteObject.MyObject app=new RemoteObject.MyObject();
MyDelegate md=new MyDelegate(app.ALongTimeMethod);
IAsyncResult Iar=md.BeginInvoke(1,2,1000,null,null);
Method();
if(!Iar.IsCompleted)
{
Iar.AsyncWaitHandle.WaitOne();
}
else
{
Console.WriteLine("結果是"+md.EndInvoke(Iar));
}
Console.WriteLine("用了"+((TimeSpan)(DateTime.Now-dt)).TotalSeconds+"秒");
Console.ReadLine();
來看一下執行結果:
現在總共執行時間接近於主執行緒的執行時間了,等於是呼叫方法基本不佔用時間。
分析一下程式碼:Iar.AsyncWaitHandle.WaitOne(); 是阻塞等待非同步方法完成,在這裡這段程式碼是不會被執行的,因為主方法完成的時候,非同步方法早就IsCompleted了,如果我們修改一下程式碼:IAsyncResult Iar=md.BeginInvoke(1,2,5000,null,null);
可以看到,主執行緒方法結束後就在等待非同步方法完成了,總共用去了接近於非同步方法的時間:5秒。
在實際的運用中,主執行緒往往需要得到非同步方法的結果,也就是接近於上述的情況,我們在主執行緒做了少量時間的工作以後最終要是要WaitOne去等待非同步操作返回的結果,才能繼續主執行緒操作。看第二個圖可以發現,非同步操作僅僅用了1秒,但是要等待3秒的主執行緒方法完成後再返回結果,這還是不科學啊。因此,我們要使用委託回撥的非同步技術。
2、回撥非同步:
{
private delegate int MyDelegate(int a,int b,int time);
private static MyDelegate md;
[STAThread]
static void Main(string[] args)
{
DateTime dt=DateTime.Now;
//RemoteObject.MyObject app=(RemoteObject.MyObject)Activator.GetObject(typeof(RemoteObject.MyObject),System.Configuration.ConfigurationSettings.AppSettings["ServiceURL"]);
RemoteObject.MyObject app=new RemoteObject.MyObject();
md=new MyDelegate(app.ALongTimeMethod);
AsyncCallback ac=new AsyncCallback(MyClient.CallBack);
IAsyncResult Iar=md.BeginInvoke(1,2,1000,ac,null);
Method();
Console.WriteLine("用了"+((TimeSpan)(DateTime.Now-dt)).TotalSeconds+"秒");
Console.ReadLine();
}
public static void CallBack(IAsyncResult Iar)
{
if(Iar.IsCompleted)
{
Console.WriteLine("結果是"+md.EndInvoke(Iar));
}
}
private static void Method()
{
Console.WriteLine("主執行緒方法開始");
System.Threading.Thread.Sleep(3000);
Console.WriteLine("主執行緒方法結束");
}
}
可以看到我上面的註釋行,去掉遠端呼叫的註釋,對下面的本地呼叫註釋,編譯後啟動服務端,再啟動客戶端就是遠端呼叫了。
非同步呼叫結束,立即就能顯示出結果,如果開啟遠端方法的話,可以看的更加清晰:
客戶端:主執行緒方法開始-》服務端:非同步方法開始-》服務端:非同步方法結束-》客戶端:結果是3-》客戶端:主執行緒方法結束-》客戶端:用了3.03125秒。
3、單向非同步就是像同步呼叫方法那樣呼叫方法,方法卻是非同步完成的,但是不能獲得方法的返回值而且不能像同步方法那樣取得所呼叫方法的異常資訊!對於不需要返回資訊的長時間方法,我們可以放手讓它去幹就行了:
遠端物件:
using System.Runtime.Remoting.Messaging;
namespace RemoteObject
{
public class MyObject:MarshalByRefObject
{
[OneWay]
public void ALongTimeMethodOneWay(int time)
{
Console.WriteLine("非同步方法開始");
System.Threading.Thread.Sleep(time);
Console.WriteLine("非同步方法結束");
}
}
}
[OneWay]屬性是Remoting.Messaging的一部分,別忘記using,下面看看客戶端程式碼:
namespace RemoteClient
{
class MyClient
{
[STAThread]
static void Main(string[] args)
{
DateTime dt=DateTime.Now;
RemoteObject.MyObject app=(RemoteObject.MyObject)Activator.GetObject(typeof(RemoteObject.MyObject),System.Configuration.ConfigurationSettings.AppSettings["ServiceURL"]);
//RemoteObject.MyObject app=new RemoteObject.MyObject();
app.ALongTimeMethodOneWay(1000);
Method();
Console.WriteLine("用了"+((TimeSpan)(DateTime.Now-dt)).TotalSeconds+"秒");
Console.ReadLine();
}
private static void Method()
{
Console.WriteLine("主執行緒方法開始");
System.Threading.Thread.Sleep(3000);
Console.WriteLine("主執行緒方法結束");
}
}
}
這次我們僅僅只能在遠端除錯,我們先讓非同步方法去做,然後就放心的做主執行緒的事情,其他不管了。
執行結果我描述一下:
客戶端:主執行緒方法開始-》服務端:非同步方法開始-》服務端:非同步方法結束-》客戶端:主執行緒方法結束-》客戶端:用了3.8秒。
上面說的三種方法,只是非同步程式設計的一部分,具體怎麼非同步呼叫遠端方法要結合實際的例子,看是否需要用到方法的返回和主執行緒方法的執行時間與遠端方法執行時間等結合起來考慮,比如上述的WaitHandle也可以用輪詢來實現:
while(Iar.IsCompleted==false) System.Threading.Thread.Sleep(10);總的來說遠端物件的非同步操作和本地物件的非同步操作是非常接近。
還可以參考msdn相關文章:
http://msdn.microsoft.com/library/chs/default.asp?url=/library/CHS/cpguide/html/cpconasynchronousprogrammingdesignpattern2.asp
相關文章
- 【譯】async 的非同步操作模式非同步模式
- 非同步操作系列之Promise物件非同步Promise物件
- 恢復之非歸檔模式下的恢復模式
- .net remoting(一)REM
- remoting技術REM
- Oracle 歸檔和非歸檔模式之間的切換Oracle模式
- Powershell tricks::Powershell RemotingREM
- Oracle歸檔模式和非歸檔模式Oracle模式
- 非歸檔模式改為歸檔模式模式
- JavaScript - 模式視窗和非模式視窗JavaScript模式
- Microsoft .Net Remoting系列專題之一:.Net Remoting基礎篇ROSREM
- Oracle的奇葩設定之非歸檔模式與RMAN備份Oracle模式
- Remoting服務端和客戶端程式該這樣模式來寫REM服務端客戶端模式
- 非父子元件之間傳值(Bus/匯流排/釋出訂閱模式/觀察者模式)元件模式
- (六)Flutter學習之Dart非同步操作詳解FlutterDart非同步
- 嚴格模式和非嚴格模式區別模式
- Dubbo的Remoting模組解析REM
- Spring Remoting: HessianSpringREM
- IIS部署Remoting總結REM
- Remoting事件機制續REM事件
- Microsoft .Net Remoting系列專題之三:Remoting事件處理全接觸ROSREM事件
- 非同步操作系列之Generator函式與Async函式非同步函式
- 歸檔模式與非歸檔模式的切換模式
- Oracle歸檔模式與非歸檔模式設定Oracle模式
- javascript - 非同步操作JavaScript非同步
- 非同步操作(一)非同步
- .net 安裝remoting服務REM
- Microsoft .NET Remoting 框架技術ROSREM框架
- 正規表示式:貪婪模式與非貪婪模式模式
- 正規表示式貪婪模式與非貪婪模式模式
- Oracle歸檔模式和非歸檔模式的區別Oracle模式
- 轉載非域模式下禁用程式模式
- 備份&恢復之四:非歸檔模式下的備份與恢復模式
- Laravel框架學習筆記之資料同步操作(sync()的使用)Laravel框架筆記
- JavaScript 非同步操作原理JavaScript非同步
- [RIP-9]RocketMQ Design RemotingMQREM
- ORACLE RAC模式下歸檔模式和非歸檔模式的切換方法Oracle模式
- C# socket 阻止模式與非阻止模式應用例項C#模式