3.18HttpClient 池化与资源管理

默认情况下,HttpClient 实例会在每次发送 HTTP 请求时被新建。但在需要频繁请求的场景中,这种做法可能引发性能瓶颈和内存占用过高的问题,特别是在压力测试期间。为了优化性能,我们可以启用 HttpClient 池化管理,以便在请求过程中复用 HttpClient 实例。

启用 HttpClient 池化管理#

默认情况下,HttpClient 实例会在每次发送 HTTP 请求时被新建。但在需要频繁请求的场景中,这种做法可能引发性能瓶颈和内存占用过高的问题,特别是在压力测试期间。为了优化性能,我们可以启用 HttpClient 池化管理,以便在请求过程中复用 HttpClient 实例。

cs
var httpRequestBuilder = HttpRequestBuilder.Get("https://furion.net/")                            .UseHttpClientPool();   // 启用 HttpClient 池化管理// 循环发送请求for (var i = 0; i < 10; i++){    await httpRemoteService.SendAsync(httpRequestBuilder);}// 释放资源以避免内存泄漏httpRequestBuilder.ReleaseResources();

添加请求结束时需释放的资源#

内存安全是每位程序开发者必须高度重视的问题。在发送 HTTP 请求的过程中,有时需要引入未托管的资源,例如,在发送文件时,需要从本地读取文件并以流的形式发送。这种情况下,若处理不当,可能会遇到流资源无法释放的问题。

为解决这一问题,我们可以添加在请求结束后,自动处理这些需要释放的资源:

cs
// 打开文件并读取文件流(没有 using)var fileStream = File.OpenRead(@"C:\Workspaces\httptest.jpg");var httpRequestBuilder = HttpRequestBuilder.Post("https://furion.net/")    .SetContent(fileStream);  // 设置请求内容    .AddDisposable(fileStream) // 添加请求结束需要释放的资源    .AddDisposables(fileStream1, fileStream2); // 支持批量添加// 发送请求var responseMessage = await httpRemoteService.SendAsync(httpRequestBuilder);// 此时,fileStream,fileStream1 和 fileStream2 已自动释放。✅

AddDisposable 方法可以接受任何实现了 IDisposable 接口的对象作为参数,并且支持重复调用,每次调用都会将新的 IDisposable 对象添加到集合中。

管理和释放资源#

请参考第 19.3.461.9.3.47 章节内容,了解如何在请求结束时释放资源以避免内存泄漏。

cs
// 释放资源以避免内存泄漏httpRequestBuilder.ReleaseResources();

以下是 ReleaseResources 方法的底层实现代码,它负责管理和释放与 HTTP 请求相关的所有资源:

cs
public void ReleaseResources(){    // 空检查    if (HttpClientPooling is not null)    {        HttpClientPooling.Release?.Invoke(HttpClientPooling.Instance);        HttpClientPooling = null;    }    // 释放可释放的对象集合    ReleaseDisposables();}internal void ReleaseDisposables(){    // 空检查    if (Disposables.IsNullOrEmpty())    {        return;    }    // 逐条遍历进行释放    foreach (var disposable in Disposables)    {        disposable.Dispose();    }    // 清空集合    Disposables.Clear();}