3.18HttpClient 池化与资源管理
默认情况下,HttpClient 实例会在每次发送 HTTP 请求时被新建。但在需要频繁请求的场景中,这种做法可能引发性能瓶颈和内存占用过高的问题,特别是在压力测试期间。为了优化性能,我们可以启用 HttpClient 池化管理,以便在请求过程中复用 HttpClient 实例。
启用 HttpClient 池化管理#
默认情况下,HttpClient 实例会在每次发送 HTTP 请求时被新建。但在需要频繁请求的场景中,这种做法可能引发性能瓶颈和内存占用过高的问题,特别是在压力测试期间。为了优化性能,我们可以启用 HttpClient 池化管理,以便在请求过程中复用 HttpClient 实例。
var httpRequestBuilder = HttpRequestBuilder.Get("https://furion.net/") .UseHttpClientPool(); // 启用 HttpClient 池化管理// 循环发送请求for (var i = 0; i < 10; i++){ await httpRemoteService.SendAsync(httpRequestBuilder);}// 释放资源以避免内存泄漏httpRequestBuilder.ReleaseResources();添加请求结束时需释放的资源#
内存安全是每位程序开发者必须高度重视的问题。在发送 HTTP 请求的过程中,有时需要引入未托管的资源,例如,在发送文件时,需要从本地读取文件并以流的形式发送。这种情况下,若处理不当,可能会遇到流资源无法释放的问题。
为解决这一问题,我们可以添加在请求结束后,自动处理这些需要释放的资源:
// 打开文件并读取文件流(没有 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.46 和 1.9.3.47 章节内容,了解如何在请求结束时释放资源以避免内存泄漏。
// 释放资源以避免内存泄漏httpRequestBuilder.ReleaseResources();以下是 ReleaseResources 方法的底层实现代码,它负责管理和释放与 HTTP 请求相关的所有资源:
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();}