2014-03-01 108 views
0

我一直在閱讀有關異步編程的好處。好處似乎太大了,不能繼續忽視它。因此,我決定立即進入異端,任務之地,等待。我創建了一個簡單的類來對我的Web Api執行多個併發的POST操作。執行多個併發任務的最佳方法是什麼?

調用方法:

... 

int tasks = 100; 
for (var i = 0; i < tasks ; i++) 
{ 
    int taskNumber = i + 1; 
    var task = Task.Run(() => Post(taskNumber , address, client)); 
} 

System.Console.ReadKey(); 

任務來運行:

private static async Task Post(int taskNumber, Uri address, HttpClient client) 
{ 
     System.Console.WriteLine("Started Task#: {0}", taskNumber); 
     Stopwatch sw = new Stopwatch(); 
     sw.Start(); 
     var status = GetDeviceStatus(); 

     var response = await client.PostAsJsonAsync<DeviceStatus>(address, status); 
     sw.Stop(); 

     if (response.IsSuccessStatusCode) 
     { 
      Uri statusUri = response.Headers.Location; 
      System.Console.WriteLine("{0}- Elapsed: {1} Path: {2}", taskNumber, sw.Elapsed, statusUri.ToString()); 
     } 
     else 
     { 
      System.Console.WriteLine("{0}- Elapsed: {1} Path: {2}", taskNumber, sw.Elapsed, response.ToString());     
     } 
    } 

的代碼按預期工作;然而,這是執行這項任務的最佳方式(赦免雙關語)?任何建議將不勝感激。

+0

我認爲使用任務是處理這種問題的好方法..我會說一個好方法..但是記住比賽條件..不要忘記讓它線程安全..否則它的完美 –

+0

只是因爲你把'線程= 100「並不意味着它使用100個線程。你所做的只是實例化100個Task對象。 TPL如何決定創建線程和安排任務取決於TPL。將它們稱爲「任務」而不是「線程」會更準確。 – Enigmativity

+1

您的代碼存在的一個問題是您對所有100個任務使用相同的「HttpClient」實例。對於調用實例方法,「HttpClient」對象不是線程安全的。您需要爲每個呼叫創建一個新的客戶端。 – Enigmativity

回答

1

我建議您使用TAP進行基於I/O的併發,而使用TPL進行基於CPU的併發。由於WebAPI調用是I/O綁定的,因此您應該使用TAP而不是TPL。

有沒有必要打電話Task.Run在這種情況下:

int requests = 100; 
for (var i = 0; i < requests; i++) 
{ 
    int taskNumber = i + 1; 
    var task = PostAsync(taskNumber, address, client); 
} 

您也可以使用Task.WhenAll的TAP基於連接:

int requests = 100; 
var tasks = Enumerable.Range(0, requests).Select(x => PostAsync(x + 1, address, client)); 
await Task.WhenAll(tasks); 

此外,HttpClient主要是線程安全的。詳情請見its MSDN page

0

我會採取的方法是使用Microsoft Reactive Framework來處理這種並行代碼而不是任務。

這裏就是我想要做的:

var query = 
    from n in Observable.Range(0, 100) 
    from r in Observable.Using(
     () => new HttpClient(), 
     client => 
      Observable 
       .Start(() => 
       { 
        var status = GetDeviceStatus(); 
        return new 
        { 
         Response = client 
          .PostAsJson<DeviceStatus>(address, status), 
         Status = status, 
        }; 
       })) 
    select new 
    { 
     Number = n, 
     r.Response, 
     r.Status, 
    }; 

由於這是一個查詢,直到調用以某種方式查詢它不會跑。這是如何:

query.Subscribe(x => 
{ 
    /* Do something with 
     x.Number, 
     x.Response, 
     x.Status, 
    */ 
}); 

這是所有在線程池處理。所有的同步都是爲你完成的。我可以將所有結果整齊地作爲匿名對象返回。

有沒有完美的方式來做這種事情,但我喜歡這種方法。

相關問題