C# HttpClient.PostAsync线程池中没有足够的可用线程来完成该操作

C# HttpClient.PostAsync线程池中没有足够的可用线程来完成该操作,c#,multithreading,http,threadpool,C#,Multithreading,Http,Threadpool,我每秒调用一次下面的代码来轮询一个摄像头,但在运行一两天后,它就停止工作了 public List<CameraEvent> GetEventsSince(CaptureTime afterDateTime) { string uri = string.Format( "http://{0}/ISAPI/channels/1/events/detect", _ipAddress); using (var client = new

我每秒调用一次下面的代码来轮询一个摄像头,但在运行一两天后,它就停止工作了

public List<CameraEvent> GetEventsSince(CaptureTime afterDateTime)
{
    string uri = string.Format(
                    "http://{0}/ISAPI/channels/1/events/detect", _ipAddress);
    using (var client = new HttpClient())
    {
        client.Timeout = TimeSpan.FromSeconds(5);
        AddBasicAuth(client);

        try
        {
            HttpResponseMessage response =
                client.PostAsync(
                    uri, new StringContent(GetPicTimeXml(afterDateTime))).Result;

            logger.Debug(
                string.Format("Status code response={0}", response.StatusCode));

            if (response.StatusCode == HttpStatusCode.Unauthorized ||
                response.StatusCode == HttpStatusCode.Forbidden)
            {
                // 401
                currentState = 2;
                return new List<CameraEvent>();
            }

            if (response.StatusCode == HttpStatusCode.OK)
            {
                // OK
                currentState = 0;
            }
            List<CameraEvent> events = new CameraHttpResponseHandler()
                                           .HandleHttpResponse(response);
            AppendPlateImages(events);
            return events;
        }
        catch (AggregateException ex)
        {
            //if (ex.InnerException is TaskCanceledException)
            //{
            //    // Timeout
            //    currentState = 1;
            //}
            logger.Error("AggregateException", ex);
        }
        catch (Exception ex)
        {
            logger.Error("Generic exception", ex);
        }

        return new List<CameraEvent>();
    }
}
public List GetEventsSince(CaptureTime afterDateTime)
{
stringuri=string.Format(
“http://{0}/ISAPI/channels/1/events/detect”;
使用(var client=new HttpClient())
{
client.Timeout=TimeSpan.FromSeconds(5);
AddBasicAuth(客户);
尝试
{
HttpResponseMessage响应=
client.PostAsync(
uri,新的StringContent(GetPicTimeXml(afterDateTime))。结果;
logger.Debug(
Format(“状态代码response={0}”,response.StatusCode));
如果(response.StatusCode==HttpStatusCode.Unauthorized||
response.StatusCode==HttpStatusCode.Forbidden)
{
// 401
当前状态=2;
返回新列表();
}
if(response.StatusCode==HttpStatusCode.OK)
{
//嗯
currentState=0;
}
列表事件=新的CameraHttpResponseHandler()
.HandleHttpResponse(响应);
附加图像(事件);
返回事件;
}
捕获(聚合异常)
{
//如果(例如InnerException是TaskCanceledException)
//{
////超时
//当前状态=1;
//}
logger.错误(“AggregateException”,ex);
}
捕获(例外情况除外)
{
logger.Error(“一般异常”,ex);
}
返回新列表();
}
}
我得到的错误是:

2015-08-17 07:59:57310[16]错误CameraHttpClient聚合异常 System.AggregateException:发生一个或多个错误。--> System.InvalidOperationException:没有足够的可用线程 在线程池中完成该操作

调用
GetEventsSince
的父线程是在循环中运行的
background worker
线程,如果这有什么区别的话


有没有人看到过这个问题,或者对什么可能导致线程耗尽有什么建议?

很难说,但是如果线程池不足的根本原因是这个方法,那么这就是异步代码在服务器上有益的一个很好的例子

HttpClient是一个异步API,这意味着如果您正确地等待调用,则释放线程并将其发送回线程池,直到调用返回。通过调用
.Result
,您将在整个调用期间阻塞线程。假设这个方法从开始到结束需要几秒钟,99.9%的时间在等待I/O(这不是一个不合理的猜测)。按照这种方式,你100%的时间都在消耗一个线程。如果将其重构为异步运行,线程消耗将下降到0.1%,平均而言,线程池会突然变得更满

因此,我首先将方法标记为
async
(使用
Task
作为返回类型),并在使用异步API时使用
wait
而不是
.Result
。我不知道CameraHttpResponseHandler.HandleHttpResponse到底做了什么,但我猜那里的I/O也有阻塞,应该也进行转换,并使用
wait
调用它


这会影响根应用程序如何调用此方法。我需要看看这些代码来建议最好的方法。可能非常适合这里—它不仅有助于定期调用异步方法,而且还支持限制并发性,以防止出现类似问题。

问题可能是您正在使用块返回
?可能这会阻止处理
HttpClient
。我进行了一些阅读,如果我返回using块内部,这应该无关紧要,因为任何出口都应该调用dispose。此方法从开始到结束通常运行多长时间?你在这附近做记录吗?如果有什么东西挂起了,而你每秒都要抓取一个新线程,这只是时间问题。这段代码不异步有什么原因吗?@DavidHawkins我在HttpClient.PostAsync上也遇到了类似的问题,我正在查看的代码也会立即访问.Result属性,正如Todd Menier在下面解释的那样,这将导致阻塞。但我的问题是,你是如何解决这个问题的?