我们正在研究一个旧的比较器。
当用户进行研究时,我们会同时调用10-30种不同的Web服务(REST,SOAP)。很经典。客户在我们的应用程序中代表每个Web服务。
所以代码就像:
//Get the request list of client to call
clientRqListToCall = BuildRequest(userContext);
List<Task> taskList = new List<Task>();
//Call the different client
Foreach (ClientRequest clientRq in clientRqListToCall) {
Task task = Task.Run(() => CallClient(clientRq));
taskList.Add(task);
}
//wait client until timeOut
Task mainWaiterTask = Task.WhenAll(taskList);
mainTask.ConfigureAwait(false);
mainTask.Wait(timeout);
简单。 (不确定是否需要configureAwait)。每个客户端的响应都存储在ClientRequest的字段中,因此我们不使用mainTask.Result(如果客户端超时,我们必须能够继续另一个客户端的响应,并且它们会超时很多!客户端调用行为很漂亮!类似于fireandforget)。
该应用程序有些旧,我们的搜索引擎是同步的。不同的Web服务的调用位于不同的CallClient callTree中,根据研究的上下文,在Web服务调用之前将调用5至15个不同的函数。每个Web服务调用都非常长(每个1至15秒)!这一点似乎很重要!这些不是ping简单ping请求。
动作/更改?
这是一个受I / O约束的问题,我们知道Task.Run对于受CPU约束的问题而不是对I / O来说运行得很好,问题是如何使此代码更好?
感谢斯蒂芬·克莱里(http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html),我们阅读了许多有关该主题的文章。 但是我们不确定我们的选择/路线图,这就是为什么我发布这张票。
我们可以使代码异步,但是我们必须对整个CallClient调用树(数百个函数)进行重新设计。这是唯一的解决方案?当然,我们可以使用布尔参数hack(https://msdn.microsoft.com/en-us/magazine/mt238404.aspx)逐一迁移Web服务。 => 我们必须从最昂贵的(就IO而言)网络服务开始,还是只有网络服务调用的数量很重要,所以我们应该从最简单的方式开始? 换句话说,如果我有1个bigs客户,平均响应为10s,数据很多,那么我们必须首先开始异步吗?或应从具有相同数据量的小数点(1-2s)开始。我可能是错的,但是线程以同步方式锁定,直到task.run()如此明显地完成了10s Task一直锁定线程,但是就I / O释放而言,尽快使用线程可能会更好。数据下载量是否重要?还是我们应该只考虑Web服务计时器?
Task.Run使用应用程序threadPool,我们必须在.Run(...)或Task.Factory.StartNew(...,TaskCreationOptions.LongRunning)之间进行选择,以便(很多时间) , 创建新线程,因此可能会更好。 =>我使用控制台应用程序对subjet进行了一些测试,.Run()在所有情况下似乎都比Task.Factory.StartNew快25%到33%。 当然,这是预期的结果,但是在拥有200个用户的网络应用中, 我不确定结果是否会相同,我担心池已满,并且任务会彼此跳下去而不会结束。 注意:如果使用startNew,则WaitAll(timeout)替换WhenAll。
今天,我们平均有20至50个客户可以同时进行调查。应用程序工作没有大问题,我们没有死锁,但是有时我们可以看到我们这边的任务执行有些延迟。我们的Cpu使用率很低(<10%),Ram也很绿色(<25%)
我知道有很多关于任务的票证,但是很难将它们合并在一起以匹配我们的问题。我们还阅读了相互矛盾的建议。
答案 0 :(得分:-1)
我以前使用Parallel.ForEach处理多个I / O操作,但我没有看到上面提到的内容。我不确定它会满足您的需要,看看传递给循环的函数是否相同。也许结合策略模式/委托,您可以实现所需的内容。