2014-02-09 70 views
1

我們有Windows服務,它從MSMQ讀取消息並逐個處理它。爲了提高性能/吞吐量,我們搬到了TPL。處理消息時我們有幾個數據庫調用和WCF調用。我們觀察到,在進行WCF呼叫時,首次呼叫會更快,但後續呼叫需要更長的時間。這裏是示例代碼。異步WCF調用需要更多時間然後同步調用

public class TestWcf 
{ 
    public void Process(string option) 
    { 
     // container for perellel tasks and WaitAll after 50 count 
     TaskContainer batch = new TaskContainer(50, true); 

     for (int i = 1; i <= 100; i++) 
     { 
      if(option.Equals("s")) 
      { 
       batch.Add(ProcessMessage); 
      } 
      else 
      { 
       batch.Add(ProcessMessageAsync); 
      } 
     } 
    } 

    public void ProcessMessage() 
    { 
     Stopwatch sw = Stopwatch.StartNew(); 

     PostingServiceClient client = new PostingServiceClient(); 
     client.UpdateArchiveStatus(Guid.Parse("B6D5C77C-330A-4B00-96BF-E91A2B5970E3"),"1234567890"); 

     sw.Stop(); 
     Console.WriteLine("Thread {0}, Elapsed Time: {1} s", Thread.CurrentThread.ManagedThreadId, sw.Elapsed.Seconds); 
     //client.Close(); 
    } 

    public void ProcessMessageAsync() 
    { 
     Stopwatch sw = Stopwatch.StartNew(); 

     PostingServiceClient client = new PostingServiceClient(); 
     var task = Task.Factory.FromAsync(
      client.BeginUpdateArchiveStatus(Guid.Parse("B6D5C77C-330A-4B00-96BF-E91A2B5970E3"), "1234567890", null, 
       null), client.EndUpdateArchiveStatus); 
     task.Wait(); 

     sw.Stop(); 
     Console.WriteLine("Thread {0}, Elapsed Time: {1} s", Thread.CurrentThread.ManagedThreadId, sw.Elapsed.Seconds); 
     //client.Close(); 
    } 

} 

我們正在使用外部團隊WCF,它託管在IIS服務器,應用程序池目標.Net 2.0中。 WCF服務端,serviceThrottling爲500,Service Service上沒有ServiceBehavior屬性定義。我們在同一時間在兩個控制檯實例之一上運行同步選項,其次是同步選項。 Sync選項比Async選項完成得快得多。我的假設是,系統在執行異步操作時不會從ThreadPool釋放任務。問題是,哪種方法更好(同步與異步WCF調用),還是在這種情況下有任何不同的方法來處理WCF調用。

+0

WCF服務端的'UpdateArchiveStatus'裏面發生了什麼? – Noseratio

+0

它使用SharePoint API來更新SharePoint列表。 – brijshah

回答

0

在我進入任何東西之前,你在使用Windows服務的框架是什麼? .Net 4.5(或更高版本)或.Net 4.0?

我之所以問是因爲如果你有async/await(你需要.NET 4.5。爲),那麼它可以極大地改變你的代碼的簡單性。

現在讓我們開始談生意吧。所以你在做什麼有一些不一致之處。

到底是什麼TaskContainer?我找不到任何文檔。

該代碼塊

var task = Task.Factory.FromAsync(
      client.BeginUpdateArchiveStatus(Guid.Parse("B6D5C77C-330A- 4B00-96BF-E91A2B5970E3"),"1234567890", null, null), 
      client.EndUpdateArchiveStatus); 

task.Wait(); 

NOT異步的。

它是同步的,因爲調用了task.Wait(),所以使用任務。使用Task會有一定的開銷,但在大多數情況下,異步和可伸縮性的好處將超過這個小的開銷。這一小部分開銷要比阻塞呼叫或阻塞線程來進行網絡呼叫要好。

如果你想真正的異步調用,你需要這樣的事:

var guid = Guid.Parse("B6D5C77C-330A-4B00-96BF-E91A2B5970E3"); 

// Since I don't have a copy of the operation contract, 
// I can't tell if the client call returns a specific type, 
// so I'm going to assume it's `void` 
var task = Task.Factory.FromAsync(client.BeginUpdateArchiveStatus, client.EndUpdateArchiveStatus, guid, null); 

// If you're using .Net 4.5 or higher 
// Another side note is that you'll want to return `async Task` instead of `async void` if you decide/can use `await` 
await task; 
sw.Stop(); 

// If you're not using .Net 4.0 
task.ContinueWith(t => 
    { 
    sw.Stop(); 
    // Whatever code you want to execute now. 
    }); 

爲了解決你的假設:

我的假設,系統不從線程池釋放的任務,而這樣做異步操作。用真正異步調用使用不會阻塞線程池線程時

Task.Factory.FromAsync。 (有噸資源,以驗證這一點,但here's是一個我快速拉昇。)

問題是,哪種方法更好(同步與異步WCF調用),或者是有什麼不同的方式來處理在這種情況下的WCF調用。

最好的辦法是正確實施異步任務。


[1]:如果你有2012 VS或更高,可以拉在NuGet包Microsoft.Bcl.Async和解決這個問題的.NET 4.0。

編輯:我剛剛意識到我碰到了一個超過1年的問題。哎呀!這就是我撇開未解答的問題所得到的結果。