我正在尝试异步发出Web请求。我的代码工作正常,除了一件事:似乎没有一种内置的方法来指定BeginGetResponse
的超时。 MSDN示例清楚地显示了一个工作示例,但它的缺点是它们都以
SomeObject.WaitOne()
这再次清楚地表明它阻止线程。我将处于高负载环境中并且无法阻塞,但如果需要超过2秒,我还需要超时请求。如果没有创建和管理单独的线程池,那么框架中是否存在可以帮助我的东西?
开始示例:
我想要的是在超时参数到期后调用BeginGetResponse()
上的异步回调的方法,并指出发生了超时。
在异步调用中,看似明显的TimeOut
参数不受尊重。
在响应返回之前,ReadWriteTimeout
参数不起作用。
非专有解决方案更可取。
修改
以下是我提出的问题:在致电BeginGetResponse
之后,我创建了一个Timer
,其持续时间是处理“开始”阶段的结束。现在请求将完成并且我的“结束”阶段将被调用或者超时期限将到期。
为了检测比赛并拥有一名获胜者,我打电话以线程安全的方式递增一个“已完成”的计数器。如果“timeout”是第一个返回的事件,我中止请求并停止计时器。在这种情况下,当调用“end”时,EndGetResponse
会抛出错误。如果首先发生“结束”阶段,它会递增计数器并且“超时”放弃中止请求。
这似乎与我想要的一样,同时还提供可配置的超时。缺点是额外的计时器对象和我不费力避免的回调。我看到1-3个线程处理各个部分(开始,超时,结束)所以它看起来像这样工作。而且我没有任何“等待”电话。
我是否错过了太多的睡眠,或者我找到了一种方法来服务我的请求而不会阻塞?
int completed = 0;
this.Request.BeginGetResponse(GotResponse, this.Request);
this.timer = new Timer(Timedout, this, TimeOutDuration, Timeout.Infinite);
private void Timedout(object state)
{
if (Interlocked.Increment(ref completed) == 1)
{
this.Request.Abort();
}
this.timer.Change(Timeout.Infinite, Timeout.Infinite);
this.timer.Dispose();
}
private void GotRecentSearches(IAsyncResult result)
{
Interlocked.Increment(ref completed);
}
答案 0 :(得分:0)
您可以使用BackgroundWorker
将HttpWebRequest
运行到一个单独的线程中,这样您的主线程仍然有效。所以,这个后台线程将被阻止,但第一个不会。
在这种情况下,您可以像使用HttpWebRequest.BeginGetResponse()
方法一样使用ManualResetEvent.WaitOne()
。
答案 1 :(得分:0)
这是什么类型的应用程序?这是一个服务进程/ Web应用程序/控制台应用程序吗?
您如何创建工作量(即请求)?如果你有一个需要完成的工作队列,你可以开始'N'个异步请求(使用你构建的超时框架)然后,一旦每个请求完成(无论是超时还是成功)你可以从队列中获取下一个请求。
这将成为生产者/消费者模式。
因此,如果您将应用程序配置为最多有“N”个未完成请求,则可以维护一个“N”个定时器池,您可以在这些请求之间重复使用(不需要处理)。
或者,您也可以使用ThreadPool.SetTimerQueueTimer()来管理您的计时器。线程池将为您管理计时器,并在请求之间重用计时器。
希望这有帮助。
答案 2 :(得分:0)
似乎我原来的方法是最好的方法。
答案 3 :(得分:0)
如果您可以使用async / await那么
private async Task<WebResponse> getResponseAsync(HttpWebRequest request)
{
var responseTask = Task.Factory.FromAsync(request.BeginGetResponse, ar => (HttpWebResponse)request.EndGetResponse(ar), null);
var winner = await (Task.WhenAny(responseTask, Task.Delay(new TimeSpan(0, 0, 20))));
if (winner != responseTask)
{
throw new TimeoutException();
}
return await responseTask;
}