我有一个性能优化问题,已经困扰我一段时间了。我曾试图从它身上挤出更多的性能,但收效甚微。
系统(简化)如下:
1)请求通过HTTP Post进入(我需要同步/内联响应)
2)我处理请求,并返回一个响应(全XML)
3)如果我在15秒内没有准备好结果,我用"服务器忙,稍后再试"类型的消息响应。
作为中央消息处理机制,我使用了基于任务的方法来排队、启动和等待消息(最多15秒)
当消息几乎是即时处理时,吞吐量(每秒请求数)相当不错(1000/s)。然而,当消息处理延迟200ms时,这将严重降低到40/s
几个片段:
<>之前AddMessage(){Task.Factory.StartNew (() =>{返回worker.ProcessMessage ();};}public messagerresponse (){task.Task。等待(15 * 1000);开关(task.Status){TaskStatus。运行:message = "您的请求花费的时间比平常长"打破;TaskStatus。RanToCompletion:message = (messagerresponse)task.Result;打破;}返回消息;}之前注意:
任务创建选项无/Longrunning/PreferFairness无影响。当运行visual studio性能分析器时,我可以直观地看到Longrunning为每个请求(预期的)创建一个新线程,而None使用有限的数量(底层线程池)来服务请求。
查看ANTS性能分析器和Visual studio性能分析器,没有争用的并发性问题,也没有其他明显浪费时间的地方(cpu时间或时钟时间)
从可视化结果中可以清楚地看出,在假设有1000个请求排队的情况下,90%的程序时间花在线程服务和上下文切换上
(显然非常昂贵)。我的结论是等待结果(在多个请求中)是非常昂贵的。
如果我在网页或WPF表单上这样做,我可以使它完全异步,但是我没有这个选项。
是否有任何地方我可以改变消息处理机制,以更好地优化并发?我对任何方法都持开放态度,如果有好处的话,我甚至会探索async/await。
提前感谢:)
我猜您看到的性能下降是由于每个请求使用两个线程。
既然你提到你对async
/await
持开放态度,我会尝试这样做:
public async Task<MessageResponse> GetResult(Message message)
{
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(15));
try
{
return await Task.Run(() => worker.ProcessMessage(message, cts.Token));
}
catch (OperationCanceledException)
{
return "Your request is taking longer than usual";
}
}
您还必须修改ProcessMessage
以定期调用CancellationToken.ThrowIfCancellationRequested
。另外,如果您的消息处理是I/o绑定的,而不是cpu绑定的,则应该将ProcessMessage
更改为async
。