代码之家  ›  专栏  ›  技术社区  ›  No Refunds No Returns

如何在HttpWebRequest.BeginGetResponse上指定超时值而不阻塞线程

  •  3
  • No Refunds No Returns  · 技术社区  · 15 年前

    BeginGetResponse . MSDN示例清楚地显示了一个工作示例,但它的缺点是它们最终都以一个

    SomeObject.WaitOne()
    

    这再一次清楚地表明它阻塞了线程。我将在一个高负载的环境,不能有阻塞,但我也需要超时,如果它需要超过2秒的请求。除了创建和管理一个单独的线程池之外,框架中是否已经存在一些可以帮助我的东西?

    起始示例:

    我想要的是上异步回调的一种方式 BeginGetResponse()

    表面上显而易见的问题 TimeOut 在异步调用中不使用参数。 这个 ReadWriteTimeout 参数在响应返回之前不起作用。

    编辑:

    我想到的是:打电话之后 ,我创建了一个 Timer

    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);
    }
    
    4 回复  |  直到 8 年前
        1
  •  0
  •   Rubens Farias    15 年前

    你可以使用 BackgroundWorker 运行您的 HttpWebRequest

    在这种情况下,您可以使用 ManualResetEvent.WaitOne() HttpWebRequest.BeginGetResponse() 方法。

        2
  •  0
  •   feroze    15 年前

    这是什么样的应用程序?这是服务进程/web应用程序/控制台应用程序吗?

    因此,如果您将应用程序配置为最多有“N”个未完成的请求,那么您可以维护一个“N”个计时器池,以便在请求之间重用(无需处理)。

    或者,您也可以使用ThreadPool.SetTimerQueueTimer()来管理计时器。线程池将为您管理计时器,并在请求之间重用计时器。

        3
  •  0
  •   No Refunds No Returns    15 年前

    看来我原来的方法是最好的。

        4
  •  0
  •   rnofenko    10 年前

    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;
            }