在ASP.NET中并行执行.NET HttpWebRequests的建议
我有一个ASP.NET MVC Web应用程序,可以对其他服务器进行REST样式的Web服务调用。 我有一个场景,我正在对两个单独的服务进行两次HttpWebRequest调用。 我需要他们两个完成继续,但他们的顺序无关紧要。 它们可能每个需要1-2秒,我现在按顺序运行它们。 并行运行会减少用户响应时间,但最好的方法是什么?
在研究这个时,我可以想到几个选择:
我需要找到一个既能运作又能大规模运行的解决方案。 这就是我担心线程池大小的原因。 我不愿意阻止请求,因为他们正在等待可用的线程。
我喜欢手动执行此类操作,而不是依赖异步Web请求或线程池的自动resize(默认情况下为25个线程)。 当然,这些是解决问题的完美方法,但我认为以下代码更具可读性(在下面的示例中,_links将在处理之前包含链接列表…):
private static IList _links = new List (); private const int NumberOfThreads = 2; public void SpawnWebRequests() { IList threadList = new List (); for (int i = 0; i < NumberOfThreads; i++) { var thread = new Thread(ProcessWebRequests); threadList.Add(thread); thread.Start(); } for (int i = 0; i < NumberOfThreads; i++) { threadList[i].Join(); } } private static void ProcessWebRequests() { String link; while (true) { lock(_links) { if (_links.Count == 0) break; link = _links.RemoveAt(0); } ProcessWebRequest(link); } } private static void ProcessWebRequest(String link) { try { var request = (HttpWebRequest)WebRequest.Create(link); request.Method = "HEAD"; // or "GET", since some sites (Amazon) don't allow HEAD request.Timeout = DefaultTimeoutSeconds * 1000; // Get the response (throws an exception if status != 200) using (var response = (HttpWebResponse)request.GetResponse()) { if (response.StatusCode == HttpStatusCode.OK) Log.Debug("Working link: {0}", request.RequestUri); } } catch (WebException ex) { var response = ((HttpWebResponse)ex.Response); var status = response != null ? response.StatusCode : HttpStatusCode.RequestTimeout; Log.WarnException(String.Format("Broken link ({0}): {1}", status, link), ex); // Don't rethrow, as this is an expected exception in many cases } catch (Exception ex) { Log.ErrorException(String.Format("Error processing link {0}", link), ex); // Rethrow, something went wrong throw; } }
如果您只想管理线程池的大小(如果您使用的是ThreadPool.QueueUserWorkItem()),则可以使用ThreadPool.SetMaxThreads = 2)。
当然,如果您想使用Microsoft认可的异步方法,请查看此示例: http : //msdn.microsoft.com/en-us/library/86wf6409.aspx 。 只需确保清理每个响应(通过“使用”块或关闭响应对象)!
希望有所帮助,诺亚
multithreadingWebRequests的一个答案,一个好的和稳定的方法? :CSharp使用ManualResetEvent event = new ManualResetEvent()
,一个等于飞行请求数的引用计数器和Interlocked.Decrement
来控制event.Set()
。 然后主线程通过调用event.WaitOne()
等待。
但是, WaitHandles – Auto / ManualResetEvent和Mutex提到,ManualResetEvent“可能比使用Wait,Pulse和PulseAll等各种Monitor方法慢得多。
我最终将我的代码从Noah Blumenthal博客文章中删除: 运行通用任务async(流利的) 。 我做了两个更改:实现IDisposable
并在ManualResetEvent
上调用.Close()
并从使用lock()
切换到Interlocked
.Decrement()
和.Decrement()
。
public class AsyncQueueManager : IDisposable { private readonly ManualResetEvent waitHandle = new ManualResetEvent(true); private int count = 0; public AsyncQueueManager Queue(Action
我建议您创建一个执行HttpWebRequest的工作类,并在每个连接的自己的线程中启动它。 你可以加入线程并等到它们都完成,或者传递一个回调方法。 在任何一种情况下,您都需要考虑连接失败,超时和其他exception。 我更喜欢使用一个返回连接结果的回调和线程的ManagedThreadId,我用它来跟踪线程。 worker类应该捕获所有exception,以便您可以在调用类中处理它们。
本文提供了一些有关何时超过最大连接数的见解和修复: http : //support.microsoft.com/kb/821268 。
除非您正在做一些花哨的事情,否则ThreadPool的大小是固定的,并且通常足够大以满足您的需求。 在您的特定情况下,如果您的Web服务负载很重并且每个调用者已为其自己的回调启动了2个TP线程,则可能会遇到使用AsyncIO调用的资源约束问题。
也许最简单的实现可能是拥有两个不同的回调函数,一个用于service1,一个用于每个CompletionEvents中的service2,将一些触发变量设置为“true”,然后在主线程中等待两个触发变量的设置。 您可以使用ResetEvents执行此操作,但如果您的服务器处于负载状态,您可能希望避免这种情况。
该过程的伪代码可能是:
Dictionary callCompleted = new Dictionary string operation1Key = Guid.NewGuid().ToString(); string operation2Key = Guid.NewGuid().ToString(); callCompleted[operation1Key] = false; callCompleted[operation2Key] = false; //make your remote calls and pass the operation key as the data //.... //.... bool waiting = true; while (waiting) { bool isFinished = true; foreach(string operationKey in callCompleted.Keys) { isFinished &= callCompleted[operationKey] if (!isFinished) { break; } } waiting = !isFinished; }
由于我不知道你如何打电话的确切性质,它有点激动,但它应该运作得相当好。
上述就是C#学习教程:在ASP.NET中并行执行.NET HttpWebRequests的建议分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/1039012.html