编辑
2025-09-17
C#
00

目录

对象池的概念与价值
C#对象池的基本实现
实战应用:网络连接池实现
调用
微软官方的对象池:Microsoft.Extensions.ObjectPool
总结

对象池是C#中一种强大的性能优化技术,对于开发高性能、高并发应用具有极其重要的意义。本文将从概念到实践,详细讲解C#对象池的实现与应用,帮助你在实际项目中充分利用这一技术提升应用性能。

对象池的概念与价值

对象池是一种设计模式,通过预先创建并重复使用对象,避免频繁的对象创建和销毁操作。在C#应用中,这种技术能够:

  • 减少GC压力:降低垃圾回收器的工作负担
  • 提高性能:避免频繁内存分配带来的性能开销
  • 优化资源利用:更合理地管理系统资源

C#对象池的基本实现

下面是一个功能完整的对象池泛型实现,通过注释详细解释了每个部分的作用:

C#
using System; using System.Collections.Concurrent; /// <summary> /// 通用对象池实现,可重复使用对象以减少内存分配 /// </summary> /// <typeparam name="T">对象池中管理的对象类型,必须有无参构造函数</typeparam> public class ObjectPool<T> where T : class, new() { // 使用线程安全的并发集合存储对象,保证多线程环境下的安全访问 private readonly ConcurrentBag<T> _pool = new ConcurrentBag<T>(); // 对象池最大容量,防止无限制增长 private readonly int _maxSize; // 对象创建委托,可自定义对象创建逻辑 private readonly Func<T> _objectGenerator; /// <summary> /// 构造函数 /// </summary> /// <param name="maxSize">对象池最大容量,默认100</param> /// <param name="initialSize">初始预创建对象数量,默认10</param> public ObjectPool(int maxSize = 100, int initialSize = 10) { _maxSize = maxSize; _objectGenerator = () => new T(); // 预先创建初始对象填充池 for (int i = 0; i < initialSize; i++) { _pool.Add(_objectGenerator()); } } /// <summary> /// 从对象池获取对象 /// </summary> /// <returns>可用的对象实例</returns> public T Get() { // 尝试从池中获取已有对象 if (_pool.TryTake(out T item)) { return item; } // 如果池为空,创建新对象 return _objectGenerator(); } /// <summary> /// 归还对象到对象池 /// </summary> /// <param name="item">要归还的对象</param> public void Return(T item) { // 检查对象池是否已达到最大容量 if (_pool.Count < _maxSize) { _pool.Add(item); } // 超出容量的对象将被丢弃,由GC回收 } }

实战应用:网络连接池实现

以下是一个实际的网络连接池应用示例,展示如何利用对象池管理TCP连接:

C#
using System; using System.Net.Sockets; /// <summary> /// 网络连接池,用于管理和复用TCP连接 /// </summary> public class NetworkConnectionPool { // 内部使用通用对象池管理TcpClient实例 private readonly ObjectPool<TcpClient> _connectionPool; /// <summary> /// 构造网络连接池 /// </summary> /// <param name="maxConnections">最大连接数,默认50</param> public NetworkConnectionPool(int maxConnections = 50) { _connectionPool = new ObjectPool<TcpClient>( maxSize: maxConnections, initialSize: 10 ); } /// <summary> /// 获取一个可用的网络连接 /// </summary> /// <param name="host">目标主机地址</param> /// <param name="port">目标端口</param> /// <returns>建立好的TCP连接</returns> public TcpClient AcquireConnection(string host, int port) { // 从池中获取连接 TcpClient connection = _connectionPool.Get(); // 检查连接状态,必要时重新建立连接 if (!connection.Connected) { connection.Connect(host, port); } return connection; } /// <summary> /// 释放连接回连接池 /// </summary> /// <param name="connection">要释放的连接</param> public void ReleaseConnection(TcpClient connection) { // 重置连接状态,准备重用 connection.Close(); _connectionPool.Return(connection); } }

调用

C#
using System.Net.Sockets; using System.Text; namespace AppObjectPool { internal class Program { static async Task Main(string[] args) { // 创建网络连接池实例,最大支持30个连接 NetworkConnectionPool connectionPool = new NetworkConnectionPool(maxConnections: 30); Console.WriteLine("网络连接池示例演示开始..."); // 模拟多个并发请求场景 await SimulateMultipleRequests(connectionPool); Console.WriteLine("按任意键退出..."); Console.ReadKey(); } /// <summary> /// 模拟多个并发网络请求 /// </summary> static async Task SimulateMultipleRequests(NetworkConnectionPool connectionPool) { // 定义目标服务器信息 string host = "163.com"; int port = 80; // 创建多个并发任务 Task[] tasks = new Task[10]; for (int i = 0; i < tasks.Length; i++) { int requestId = i; tasks[i] = Task.Run(async () => { await SendHttpRequest(connectionPool, host, port, requestId); }); } // 等待所有请求完成 await Task.WhenAll(tasks); Console.WriteLine("所有请求已完成"); } /// <summary> /// 发送一个HTTP请求并处理响应 /// </summary> static async Task SendHttpRequest(NetworkConnectionPool connectionPool, string host, int port, int requestId) { Console.WriteLine($"请求 {requestId}: 开始发送..."); TcpClient connection = null; try { // 从连接池获取一个连接 connection = connectionPool.AcquireConnection(host, port); Console.WriteLine($"请求 {requestId}: 已获取连接"); // 创建简单的HTTP GET请求 string request = $"GET / HTTP/1.1\r\nHost: {host}\r\nConnection: keep-alive\r\n\r\n"; byte[] requestData = Encoding.ASCII.GetBytes(request); // 获取网络流 NetworkStream stream = connection.GetStream(); // 发送请求 await stream.WriteAsync(requestData, 0, requestData.Length); Console.WriteLine($"请求 {requestId}: 数据已发送"); // 读取响应 byte[] responseBuffer = new byte[4096]; int bytesRead = await stream.ReadAsync(responseBuffer, 0, responseBuffer.Length); string response = Encoding.ASCII.GetString(responseBuffer, 0, bytesRead); // 打印响应标头 string headerPart = response.Substring(0, Math.Min(200, response.Length)); Console.WriteLine($"请求 {requestId}: 收到响应 - {headerPart.Replace("\r\n", " | ")}..."); // 模拟处理响应数据 await Task.Delay(100); } catch (Exception ex) { Console.WriteLine($"请求 {requestId}: 发生错误 - {ex.Message}"); } finally { // 重要:使用完毕后务必归还连接到池中 if (connection != null) { connectionPool.ReleaseConnection(connection); Console.WriteLine($"请求 {requestId}: 连接已归还到连接池"); } } } } }

image.png

微软官方的对象池:Microsoft.Extensions.ObjectPool

除了自定义实现,.NET Core提供了官方的对象池库:

image.png

C#
using Microsoft.Extensions.ObjectPool; using System; using System.Collections.Generic; using System.Diagnostics; using System.Threading; using System.Threading.Tasks; namespace AppObjectPool { /// <summary> /// 演示用的复杂对象,表示一个资源密集型计算器 /// </summary> public class MyClass { // 模拟大型资源 private readonly byte[] _buffer; public string Name { get; set; } public int OperationCount { get; private set; } public MyClass() { // 模拟耗时的对象初始化过程 _buffer = new byte[1024 * 1024]; // 分配1MB内存 Thread.Sleep(10); // 模拟耗时的初始化 Console.WriteLine("创建了新的MyClass实例"); } /// <summary> /// 模拟对象的业务操作 /// </summary> /// <param name="input">输入数据</param> /// <returns>计算结果</returns> public int PerformOperation(int input) { // 模拟一些计算操作 for (int i = 0; i < 1000; i++) { _buffer[i % _buffer.Length] = (byte)(input % 256); } OperationCount++; return input * 2; } /// <summary> /// 重置对象状态以便重用 /// </summary> public void Reset() { // 清理对象内部状态 Array.Clear(_buffer, 0, _buffer.Length); Name = null; OperationCount = 0; Console.WriteLine("重置了MyClass实例状态"); } } /// <summary> /// 对象池策略类,定义如何创建和重置对象 /// </summary> public class MyClassPolicy : PooledObjectPolicy<MyClass> { public override MyClass Create() { // 创建新对象的逻辑 MyClass obj = new MyClass(); Console.WriteLine("策略创建了新的MyClass实例"); return obj; } public override bool Return(MyClass obj) { // 重置对象状态的逻辑 obj.Reset(); return true; // 返回true表示对象可以重用 } } /// <summary> /// 自定义的对象池,用于演示如何控制最大容量 /// </summary> public class CustomObjectPool<T> : DefaultObjectPool<T> where T : class { private readonly int _maxCapacity; public CustomObjectPool(IPooledObjectPolicy<T> policy, int maximumRetained) : base(policy, maximumRetained) { _maxCapacity = maximumRetained; } public int MaxCapacity => _maxCapacity; } internal class Program { static async Task Main(string[] args) { Console.WriteLine("===== Microsoft.Extensions.ObjectPool 使用示例 ====="); // 1. 基本使用示例 Console.WriteLine("\n基本使用示例:"); BasicPoolExample(); Console.WriteLine("\n按任意键退出..."); Console.ReadKey(); } /// <summary> /// 演示对象池的基本使用 /// </summary> static void BasicPoolExample() { // 创建对象池策略 var policy = new MyClassPolicy(); // 直接创建对象池,指定最大容量为20 var pool = new DefaultObjectPool<MyClass>(policy, 20); // 可选:使用自定义对象池包装器来获取最大容量信息 var customPool = new CustomObjectPool<MyClass>(policy, 20); Console.WriteLine($"对象池已创建,最大容量: {customPool.MaxCapacity}"); // 从池中获取对象 MyClass obj1 = customPool.Get(); obj1.Name = "实例1"; Console.WriteLine($"从池中获取了对象 {obj1.Name}"); // 使用对象执行操作 int result = obj1.PerformOperation(42); Console.WriteLine($"使用对象执行操作,结果: {result}"); // 归还对象到池中 (重要!) customPool.Return(obj1); Console.WriteLine("对象已归还到池中"); // 再次获取对象 (通常会得到同一个已重置的实例) MyClass obj2 = customPool.Get(); obj2.Name = "实例2"; Console.WriteLine($"再次从池中获取了对象 {obj2.Name}"); // 归还第二个对象 customPool.Return(obj2); Console.WriteLine("第二个对象已归还到池中"); } } }

image.png

总结

C#对象池是一项强大的性能优化技术,通过重用对象减少内存分配和垃圾回收的压力。在高性能应用、高并发系统中,合理使用对象池可以显著提升应用性能和资源利用率。

掌握对象池的实现原理和应用技巧,将帮助开发者构建更高效、更可靠的C#应用程序。无论是自定义对象池还是使用官方提供的对象池,关键在于了解其适用场景并遵循相关最佳实践。


你是否在项目中遇到过性能瓶颈?尝试过使用对象池进行优化吗?欢迎在评论区分享你的经验和看法!

#C#编程技巧 #性能优化 #对象池 #内存管理 #高并发 #DotNet开发 #编程最佳实践

本文作者:技术老小子

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!