public async Task<object> Post([FromBody]string data) { object response = ExecuteServerLogics(data); return response; }
上面的代码工作得很好,但在一些客户的电话中,我们遇到了性能问题.
在这里阅读了一些文章后,我注意到我们的webApi休息服务,
并没有真正与其传入的Web请求异步工作,
因为我们忘了使用async / await模式:
public async Task<object> Post([FromBody]string data) { object response = await Task<object>.Run( () => { return ExecuteServerLogics(data); }); return response; }
在此修复后,我们注意到性能变得更好,
但我们发现了另一个批评问题:
访问HttpContext.Current时 – 它返回Null引用:
public async Task<object> Post([FromBody]string data) { object response = await Task<object>.Run( () => { var currentContext = HttpContext.Current; // Returns Null! return ExecuteServerLogics(data); }); return response; }
我们试图找到一个解决方案,在大多数帖子中我们发现我们应该通过
worker thread的HttpContext引用到执行服务器逻辑的内部Task.
这个解决方案的问题是服务器的逻辑方法,使用许多使用的静态类
“HttpContext.Current”如 –
>记录器调用.
>检索user.identity的静态安全性类
>静态安全类,用于检索传入请求的会话数据等.
因此,传递工作线程的“HttpContext.Current”引用将无法解决它.
当我们尝试下一个解决方案时:
public async Task<object> Post([FromBody]string data) { // Save worker context: var currentContext = HttpContext.Current; object response = await Task<object>.Run( () => { // Set the context of the current task : HttpContext.Current = currentContext ; // Causes the calls not to work asynchronously for some reason! // Executes logics for current request: return ExecuteServerLogics(data); }); return response; }
出于某种原因,我们注意到性能再次恶化,就像它再次同步恢复工作一样.
我们的问题是:
1.为什么在最后一个例子中,在await任务中设置“HttpContext.Current”,
导致请求返回与同步结果类似的相同不良性能结果?
2.还有另一种方法我们可以在调用的内部任务中使用“HttpContext.Current” – “ExecuteServerLogics”,
并且在所有静态类中也称为“HttpContext.Current”?
我以某种方式做错了整个设计吗?
谢谢!
解决方法
public async Task<object> Post([FromBody]string data) { object response = ExecuteServerLogics(data); return response; }
不要忽略编译器警告;编译器将为此方法生成警告,该警告明确指出它将同步运行.
继续:
in some of the client’s calls,we experienced performance issues.
对于单独的单个调用,服务器上的异步代码将不会更快.它只能帮助您扩展服务器.
特别是,Task.Run将否定异步的所有性能优势,然后将性能降低一点.我相信你所测量的性能改善是巧合的.
in most posts we found that we should pass the worker thread’s HttpContext reference into the inner Task that executes the server logics.
这些帖子是错误的.恕我直言.当该对象专门设计为仅从请求线程访问时,您最终会使用后台线程中的HttpContext对象.
am I doing the entire design wrong somehow?
我建议你退后一步,考虑一下大局.当请求进入时,它有一定的工作量.这项工作是同步还是异步完成对客户来说无关紧要;两种方法都需要大约相同的时间.
如果您需要尽早返回客户端,那么您将需要一个完全不同的架构.通常的方法是将工作排队到可靠的队列(例如,Azure队列),具有单独的后端(例如,Azure WebRole),并且在工作完成时主动通知客户端(例如,SignalR).
但这并不是说async是无用的.如果ExecuteServerLogics是一个I / O绑定方法,那么它应该是异步而不是阻塞,然后您可以使用异步方法:
public async Task<object> Post([FromBody]string data) { object response = await ExecuteServerLogicsAsync(data); return response; }
这将使您的服务器整体上更具响应性和可扩展性(即,不会被许多请求所淹没).