在ASP.NET中并行执行.NET HttpWebRequests的建议 [英] Recommendations for executing .NET HttpWebRequests in parallel in ASP.NET
问题描述
我有一个ASP.NET MVC Web应用程序,可以对其他服务器进行REST风格的Web服务调用.我有一个场景,其中我对两个单独的服务进行了两个HttpWebRequest调用.我需要它们都完成才能继续,但是它们的顺序无关紧要.它们每个可能需要1-2秒,我现在正在按顺序运行它们.并行运行它们会减少用户响应时间,但是最好的方法是什么?
I have an ASP.NET MVC web application that makes REST style web service calls to other servers. I have a scenario where I am making two HttpWebRequest calls to two separate services. I need them both to complete to continue, but their order doesn't matter. They may take 1-2 seconds each and I am running them in sequence now. Running them in parallel would decrease the user response time, but what is the best way?
在研究这个问题时,我可以想到几种选择:
In researching this, I can think of several options:
- 在主线程上执行一个请求,然后为另一个请求启动另一个线程.应该创建新线程还是使用线程池?如果我使用游泳池,如何确定其大小?另外,不确定如何将线程重新连接在一起(例如,使用 ThreadPool.RegisterWaitForSingleObject )?
- 尝试并利用内置的 IAsyncResult 支持对于一个或两个请求.同样,不确定异步请求在哪个线程上执行,因此不确定如何确定线程池的大小.如何将IAsyncResult重新加入主线程?所有示例都在回调中找到过程信息,但是我可以在主线程中等待并使用
- Execute one request on the main thread, and spin up a second thread for the other request. Should created new threads or use a thread pool? If I use a pool, how do I size it? Also, not sure how I can join the threads back together (e.g. use ThreadPool.RegisterWaitForSingleObject)?
- Try and leverage the built-in IAsyncResult support for one or both of the requests. Again, not sure on which threads the async request execute, so not sure how to size the thread pool. How do I join IAsyncResult back into my main thread? All the examples I find process information in the callback, but I can just wait in my main thread and use the IsCompleted property?
我需要找到一个既可以运行又可以大规模执行的解决方案.这就是为什么我担心线程池的大小.我不希望请求阻塞,因为它们正在等待可用线程.
I need to find a solution that will both function, and perform at scale. That is why I am worried about thread pool sizing. I would hate to have requests blocking because they are waiting for available threads.
推荐答案
One of the answers to Multithreading WebRequests, a good and stable approach? : CSharp uses a ManualResetEvent event = new ManualResetEvent()
, a reference counter equaling the number of in flight requests and Interlocked.Decrement
to control the event.Set()
. The main thread then waits by calling event.WaitOne()
.
但是, WaitHandles-Auto/ManualResetEvent和Mutex 提到"ManualResetEvent"可能比使用各种Monitor方法(例如Wait,Pulse和PulseAll)要慢得多.
However, WaitHandles - Auto/ManualResetEvent and Mutex mentions that ManualResetEvent "can be significantly slower than using the various Monitor methods" like Wait, Pulse and PulseAll.
我最终基于Noah Blumenthal的博客文章编写了代码:
I ended up basing my code off of this Noah Blumenthal blog post: Run generic tasks async (fluent-ly). I did make two changes: implement IDisposable
and call .Close()
on the ManualResetEvent
and switch from using a lock()
to Interlocked
.Increment()
and .Decrement()
.
public class AsyncQueueManager : IDisposable {
private readonly ManualResetEvent waitHandle = new ManualResetEvent(true);
private int count = 0;
public AsyncQueueManager Queue(Action<object> action) {
Interlocked.Increment(ref count);
waitHandle.Reset();
Action<object> actionWrapper = CreateActionWrapper(action);
WaitCallback waitCallback = new WaitCallback(actionWrapper);
ThreadPool.QueueUserWorkItem(waitCallback);
return this;
}
private Action<object> CreateActionWrapper(Action<object> action) {
Action<object> actionWrapper = (object state) =>
{
try {
action(state);
} catch (Exception ex) {
// log
} finally {
if (Interlocked.Decrement(ref count) == 0) {
waitHandle.Set();
}
}
};
return actionWrapper;
}
public void Wait() {
waitHandle.WaitOne();
}
public void Wait(TimeSpan timeout) {
waitHandle.WaitOne(timeout);
}
public void Dispose() {
waitHandle.Close();
}
}
这篇关于在ASP.NET中并行执行.NET HttpWebRequests的建议的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!