2011-11-09 132 views
8

我正在實現一個異步服務。在評估微軟的example之後,我想知道他們的方法是否真的是異步的。我很確定它是這樣的,但是我在網上看到的一些樣本和參數AsyncCallback引起我的疑惑。真正異步的WCF服務

根據實例,我們需要實現開始方法對這樣的:

public IAsyncResult BeginGetAcmeAnvil(AsyncCallback callback, object state) 
{ 
    // Starts synchronous task 
    var acmeAsyncResult = new AcmeAsyncResult<Anvil> 
    { 
    Data = new Anvil() 
    };  
    return acmeAsyncResult; 
} 

public Anvil EndGetAcmeAnvil(IAsyncResult result) 
{ 
    var acmeAsyncResult = result as AcmeAsyncResult<Anvil>; 

    return acmeAsyncResult != null 
    ? acmeAsyncResult.Data 
    : new Anvil(); 
} 

很簡單,但爲什麼我們有一個AsyncCallback參數?我們是不是應該撥打電話callback,這又會觸發End方法?

這是我的想法:

public delegate void AsyncMethodCaller(AcmeAsyncResult<Anvil> acmeAsyncResult, 
             AsyncCallback callback); 

public IAsyncResult BeginGetAcmeAnvil(AsyncCallback callback, object state) 
{ 
    var acmeAsyncResult = new AcmeAsyncResult<Anvil>(); 
    var asyncMethodCaller = new AsyncMethodCaller(GetAnvilAsync); 

    // Starts asynchronous task 
    asyncMethodCaller.BeginInvoke(acmeAsyncResult, callback, null, null); 

    return acmeAsyncResult; 
} 

private void GetAcmeAnvilAsync(AcmeAsyncResult<Anvil> acmeAsyncResult, 
           AsyncCallback callback) 
{ 
    acmeAsyncResult.Data = new Anvil(); 
    callback(acmeAsyncResult); // Triggers EndGetAcmeAnvil 
} 

public Anvil EndGetAcmeAnvil(IAsyncResult result) 
{ 
    var acmeAsyncResult = result as AcmeAsyncResult<Anvil>; 

    return acmeAsyncResult != null 
    ? acmeAsyncResult.Data 
    : new Anvil(); 
} 

我沒有使用loadUI一些負載測試,但沒有明顯的性能變化。

回答

5

我發現了一個good article,解釋瞭如何從異步WCF服務中獲得最佳性能。

的要點是:

  1. 不做在繁重的工作開始方法,並
  2. 做使回調觸發方法。

下面是從文本的摘錄:

爲了獲得最佳性能,下面是當你調用/執行上述異步模式兩個原則:

  • 原則1:開始方法不要做重量級的工作...

    原因是你應該儘快返回調用線程,以便調用者可以安排其他工作。如果它是一個UI線程,應用程序需要使用該線程來響應用戶輸入。如果可能的話,你應該總是將繁重的操作放在不同的線程中

  • 原則2:避免調用結束的同一線程上方法開始方法。

    結束方法通常是阻塞的。它等待操作完成。如果實施結束方法,您會看到它實際上調用IAsyncResult.WaitHandle.WaitOne()。另一方面,作爲正常實施,這個WaitHandle是分配的延遲ManualResetEvent。只要你不叫它,它就根本不會被分配。對於快速操作,這很便宜。但是,一旦結束被調用,您將不得不分配它。撥打結束正確的地方是從回調的操作。當調用回調時,這意味着阻塞工作確實完成。在這一點上,您可以撥打結束獲取數據而不犧牲性能。

2

我認爲這樣分隔的主要原因是WCF運行時正在處理線程同步,而不是你必須手動處理它。

如果您通過回調調用end方法,則必須處理使模式更復雜的同步(如您在編碼示例中所見)。這種模式的目標不是讓你真正意識到線程化的東西,你只想編寫長時間運行的操作,而不必考慮線程的實現細節。