gpt4 book ai didi

c# - 几个小时后并行发送 HTTP 请求后 ServicePoint 对象的大小很大

转载 作者:行者123 更新时间:2023-11-30 12:26:21 25 4
gpt4 key购买 nike

我们正在使用 HttpClient 向远程 Web API 并行发送请求:

public async Task<HttpResponseMessage> PostAsync(HttpRequestInfo httpRequestInfo)
{
using (var httpClient = new HttpClient())
{
httpClient.BaseAddress = new Uri(httpRequestInfo.BaseUrl);
if (httpRequestInfo.RequestHeaders.Any())
{
foreach (var requestHeader in httpRequestInfo.RequestHeaders)
{
httpClient.DefaultRequestHeaders.Add(requestHeader.Key, requestHeader.Value);
}
}

return await httpClient.PostAsync(httpRequestInfo.RequestUrl, httpRequestInfo.RequestBody);
}
}

这个API可以被多个线程同时调用。运行大约四个小时后,我们发现发生了内存泄漏问题,从分析工具来看,似乎有两个 ServicePoint 对象,其中一个很大,大约 160 MB。

据我所知,我可以看到代码上面的一些问题:

  • 我们应该尽可能共享HttpClient 实例。在我们的例子中,请求地址和 header 可能会有很大差异,所以这是我们可以做某事的一点,还是不会对性能造成太大影响?我只是想到我们可以准备一个字典来存储和查找HttpClient实例。
  • 我们没有修改ServicePointDefaultConnectionLimit,所以默认情况下它只能同时向同一个服务器发送两个请求。如果我们把这个值改大一点,内存泄漏问题就可以解决了吗?
  • 我们还抑制了 HTTPS 证书验证:ServicePointManager.ServerCertificateValidationCallback = delegate { return true; }; 这个跟问题有关系吗?

由于这个问题不容易重现(需要很多时间),我只是需要一些想法,以便我可以优化我们的代码以长时间运行。

最佳答案

自己说明情况,以防其他人以后也遇到这个问题。

首先,这不是内存泄漏,而是性能问题。

We test our application in virtual machine, on which we opened the proxy. It leads to the internet is quite slow. So in our case, each HTTP request might cost 3-4 seconds. As time going, there will be a lot of connections in the ServicePoint queue. Therefore, it's not memory leaks, that's just because the previous connections are not finished quickly enough.

只要确保每个 HTTP 请求都没有那么慢,一切就正常了。

我们还尝试减少 HttpClient 实例,以提高 HTTP 请求性能:

private readonly ConcurrentDictionary<HttpRequestInfo, HttpClient> _httpClients;

private HttpClient GetHttpClient(HttpRequestInfo httpRequestInfo)
{
if (_httpClients.ContainsKey(httpRequestInfo))
{
HttpClient value;
if (!_httpClients.TryGetValue(httpRequestInfo, out value))
{
throw new InvalidOperationException("It seems there is no related http client in the dictionary.");
}

return value;
}

var httpClient = new HttpClient { BaseAddress = new Uri(httpRequestInfo.BaseUrl) };
if (httpRequestInfo.RequestHeaders.Any())
{
foreach (var requestHeader in httpRequestInfo.RequestHeaders)
{
httpClient.DefaultRequestHeaders.Add(requestHeader.Key, requestHeader.Value);
}
}

httpClient.DefaultRequestHeaders.ExpectContinue = false;
httpClient.DefaultRequestHeaders.ConnectionClose = true;
httpClient.Timeout = TimeSpan.FromMinutes(2);

if (!_httpClients.TryAdd(httpRequestInfo, httpClient))
{
throw new InvalidOperationException("Adding new http client thrown an exception.");
}

return httpClient;
}

在我们的例子中,对于相同的服务器地址,只有请求主体不同。我还覆盖了 HttpRequestInfoEqualsGetHashCode 方法。

同时,我们设置 ServicePointManager.DefaultConnectionLimit = int.MaxValue;

希望对您有所帮助。

关于c# - 几个小时后并行发送 HTTP 请求后 ServicePoint 对象的大小很大,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29096513/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com