2014-07-21 149 views
2

我想消耗服務引用,同時使用任務調度程序進行多個請求。該服務包含一個同步和一個返回結果集的異步函數。我有點困惑,我有幾個最初的問題,然後我會分享我在每個問題上有多遠。我正在使用一些日誌記錄,併發可視化工具和提琴手進行調查。最終,我希望使用反應式調度程序儘可能多地提出請求。任務調度程序與WCF服務參考異步功能

1)我應該使用異步函數來完成所有請求嗎?

2)如果我要在多任務中使用同步函數,那麼有限的資源可能會導致我的線程數量不足。

這是我到目前爲止有:

var myScheduler = new myScheduler(); 
var myFactory = new Factory(myScheduler); 
var myClientProxy = new ClientProxy(); 
var tasks = new List<Task<Response>>(); 
foreach(var request in Requests) 
{ 
    var localrequest = request; 
    tasks.Add(myFactory.StartNew(() => 
     { 
      // log stuff 
      return client.GetResponsesAsync(localTransaction.Request); 
      // log some more stuff 
     }).Unwrap()); 
} 

Task.WaitAll(tasks.ToArray()); 
// process all the requests after they are done 

此運行,但根據提琴手它只是試圖做所有的請求的一次。它可能是調度程序,但我相信我會做更多的事情。

我也嘗試過在沒有unwrap命令的情況下實現它,而是使用異步await委託並且它做同樣的事情。我也嘗試引用.result,並且似乎是按順序執行的。對調度程序/工廠使用非同步服務函數調用時,每個客戶端同時只能同時獲得約20個併發請求。

+0

您希望它做什麼而不是一次性發出所有請求? – i3arnon

+0

@ i3arnon - 感謝您的迴應!我有成千上萬的請求。該服務只能根據當前負載處理很多事務。我不是唯一的客戶。我想使用自定義調度程序來根據服務響應時間調整併發請求的數量。 – Ashtonian

+0

使用信號量可以更好地完成。請參閱[我的答案](http://stackoverflow.com/a/24874095/885318) – i3arnon

回答

6
  1. 是的。它將允許您的應用程序通過使用更少的線程來實現更多的擴展。
  2. 線程。當您啓動固有異步的同步操作時(例如I/O),您有一個阻塞的線程等待操作完成。但是,您可以同時使用此線程來執行CPU綁定操作。

限制併發請求量的最簡單方法是使用SemaphoreSlim它允許asynchronously wait進入它:

async Task ConsumeService() 
{ 
    var client = new ClientProxy(); 
    var semaphore = new SemaphoreSlim(100); 
    var tasks = Requests.Select(async request => 
    { 
     await semaphore.WaitAsync(); 
     try 
     { 
      return await client.GetResponsesAsync(request); 
     } 
     finally 
     { 
      semaphore.Release(); 
     } 
    }).ToList(); 
    await Task.WhenAll(tasks); 

    // TODO: Process responses... 
} 
3

不管你如何調用WCF服務是否是異步的通話或同步通話,您將受WCF serviceThrottling限制。你應該看看這些設置,並可能調高它們(如果你將它們設置爲低值,出於某種原因),在.NET4中,默認值是非常好的,但是在較早版本的.NET框架中,這些默認值更加保守比.NET4。

.NET 4.0

  • MaxConcurrentSessions:默認值是100個* ProcessorCount
  • MaxConcurrentCalls:默認值是16個* ProcessorCount
  • MaxConcurrentInstances:默認是MaxConcurrentCalls + MaxConcurrentSessions
3

1)是。 2.)是的。

如果你想控制同時請求的數量,你可以嘗試使用Stephen Toub的ForEachAsyncmethod。它允許您控制同時處理多少個任務。

public static class Extensions 
{ 
    public static Task ForEachAsync<T>(this IEnumerable<T> source, int dop, Func<T, Task> body) 
    { 
     return Task.WhenAll( 
      from partition in Partitioner.Create(source).GetPartitions(dop) 
      select Task.Run(async delegate { 
       using (partition) 
        while (partition.MoveNext()) 
         await body(partition.Current); 
      })); 
    } 
} 

void Main() 
{ 
    var myClientProxy = new ClientProxy(); 
    var responses = new List<Response>(); 

    // Max 10 concurrent requests 
    Requests.ForEachAsync<Request>(10, async (r) => 
    { 
     var response = await client.GetResponsesAsync(localTransaction.Request); 
     responses.Add(response); 
    }).Wait();  
}