2015-11-25 28 views
2

可以说我有一个控制器操作,不能做异步(由于各种原因),但我有一个服务,(通过几种方法)使用HttpClient调用休息服务。使用异步客户端并使用.Wait.Result有什么好处?或者使用同步方法的性能会降低吗?当控制器动作同步时使用异步/等待的任何理由?

因此,要么:

//MyController.cs 
public ActionResult GetSomething(int id) 
{ 
    //lots of stuff here 
    var processedResponse = _myService.Get(id); 
    //lots more stuff here 
    return new ContentResult(result); 
} 

//MyService.cs 
public ProcessedResponse Get(int id) 
{ 
    var client = new HttpClient(); 
    var result = client.Get(_url+id); 
    return Process(result); 
} 

或者:

//MyController.cs 
public ActionResult GetSomething(int id) 
{ 
    //lots of stuff here 
    var processedResponse = _myService.GetAsync(id).Result; 
    //or, .Wait, or Task.Run(...), or something similar 
    //lots more stuff here 
    return new ContentResult(result); 
} 

//MyService.cs 
public async Task<ProcessedResponse> GetAsync(int id) 
{ 
    var client = new HttpClient(); 
    var result = await client.GetAsync(_url+id); 
    return await Process(result); 
} 
+0

IMO,使服务方法'async'的唯一原因是将控制器操作重新写为'async'的计划。 – Dennis

+0

@Marius:很想知道那些“各种原因”阻止异步控制器的原因。 –

回答

5

有什么事情通过使用异步客户端和Task.Run包裹 方法来获得(()=> _myService.Get())。结果?

你最有可能最终获得的唯一的东西是死锁。想一想,你正在一个线程池线程上排队一个自然的异步方法,ASP.NET已经给你一个线程来处理你内部的Action。这没什么意义。

如果你想要去的异步,并认为你会真正从异步提供的规模效益,那么你应该重新因子你的控制器是异步以及和返回Task<T>,在那里你可以await那些异步方法。

所以我要么留同步,或重新因子代码从上到下支持异步:

//MyController.cs 
public async Task<ActionResult> GetSomethingAsync(int id) 
{ 
    //lots of stuff here 
    await GetAsync(id); 
    return new ContentResult(result); 
} 

//MyService.cs 
public async Task<ProcessedResponse> GetAsync(int id) 
{ 
    var client = new HttpClient(); 
    var result = await client.GetAsync(_url+id); 
    return await Process(result); 
} 
+0

你可以添加一个混合同步和异步代码如何发生死锁的例子..? –

+0

请注意,我没有具体询问'Task.Run()',而是关于将任务转换为同步结果(如'.Wait'和'.Result')的任何方法。我已经更新了这个问题,所以如果这些方法有任何区别,请更新您的答案以反映 – Marius

+1

'Task.Run'或不[异步代码是危险的](http:// blog。stephencleary.com/2012/07/dont-block-on-async-code.html)。 –

2

在您的方案,没有没有一个很好的理由,但让我们添加一些功能:现在

//MyController.cs 
public ActionResult GetSomething(int id) 
{ 
    //lots of stuff here 
    var processedResponse = _myService.GetAsync(id).Result; 
    //or, .Wait, or Task.Run(...), or something similar 
    //lots more stuff here 
    return new ContentResult(result); 
} 

//MyService.cs 
public async Task<ProcessedResponse> GetAsync(int id) 
{ 
    var client = new HttpClient(); 
    var pendingResult1 = client.GetAsync(_url+id); 
    var pendingResult2 = someAsyncOperation(); 
    var result3 = someSyncOperation(); 
    var result1 = await pendingResult; 
    var result2 = await pendingResult2; 
    return await Process(result1, result2, result3); 
} 

,因为您的请求需要一段时间才能完成,someAsynchOperation开始立即执行,而不是等待GetAsync()完成。 someSyncOperation也在执行中。

如果没有async关键字,您将无法使用await,因此如果您计划在功能内部执行异步执行,最好使用它。

+0

注意:如果你选择等待然后使用task.GetAwaiter()。GetResult();而不是task.Result,因此它不会在AggregateException中包装异常。 –

0

做的时候能做到这样

//MyController.cs 
public ActionResult GetSomething(int id) 
{ 
    var processedResponseTask = _myService.GetAsyn(id) 
    //lots of stuff here (1) 

    var processedResponseTask.Wait(); 
    var processedResponse = processedResponseTask.Result; 

    //lots more stuff here (2) 
    return new ContentResult(result); 
} 

现在很多的东西在这里(1)并行与异步完成任务变得有趣起来。 (或者如果你打电话给你的服务两次例如)。如果你实际上并没有在这里做很多事情(1),那么没有太大的意义。