2014-03-01 111 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, 
    */ 
}); 

这是所有在线程池处理。所有的同步都是为你完成的。我可以将所有结果整齐地作为匿名对象返回。

有没有完美的方式来做这种事情,但我喜欢这种方法。

相关问题