【发布时间】:2010-01-23 07:32:19
【问题描述】:
我正在尝试异步发出 Web 请求。我的代码工作正常,除了一件事:似乎没有内置方法可以在 BeginGetResponse 上指定超时。 MSDN 示例清楚地显示了一个工作示例,但它的缺点是它们都以
SomeObject.WaitOne()
这再次清楚地表明它阻塞了线程。我将处于高负载环境中并且不能阻塞,但如果请求超过 2 秒,我还需要超时。除了创建和管理单独的线程池之外,框架中是否已经存在可以帮助我的东西?
开始示例:
- http://msdn.microsoft.com/en-us/library/ms227433(VS.100).aspx
- http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.begingetresponse.aspx
我想要的是一种在我的超时参数到期后调用BeginGetResponse() 上的异步回调的方法,并带有一些表明发生超时的迹象。
看似明显的TimeOut 参数在异步调用中不受支持。
ReadWriteTimeout 参数在响应返回之前不会起作用。
最好使用非专有的解决方案。
编辑:
这是我想出的:在调用BeginGetResponse 之后,我创建了一个带有我的持续时间的Timer,这就是处理“开始”阶段的结束。现在,请求将完成并且我的“结束”阶段将被调用,或者超时期限将到期。
为了检测比赛并有一个获胜者,我称之为以线程安全的方式增加一个“完成”计数器。如果“超时”是第一个返回的事件,我会中止请求并停止计时器。在这种情况下,当调用“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);
}
【问题讨论】:
标签: iis asynchronous httpwebrequest timeout