谈一谈对象池SafeObjectPool能干什么

1|0前言

首先从ado.net的连接池开始了解,数据库操作通常是 new SqlConnection()、 Open()、 使用完后 Close(),整个过程相当耗时,特别是频繁建议套字接连接的过程。ado.net 驱动已经现实了连接池管理,Open() 等于申请连接,Close() 即归还资源。

Open() 的时候有几种情况:

1、有资源直接返回;

2、无可用资源,且未超过池最大设置值时,创建资源并返回;

3、无可用资源,此时会等待设置秒数,若仍然未获取资源则报错;

连接的复用使性能成数倍提升,试想网站在某一时刻突然爆增10万次,new 10万个SqlConnection对象显然会炸掉服务,创建,connect,disconnect,disponse,显然开销很大。

虽然ado.net自带的连接池已经接近完美,但在某些场合还不够用,先来一个压力测试。

2|0SafeObjectPool与dapper比武测试

[HttpGet("vs_gen")] async public Task<object> vs_gen() { var select = Tag.Select; var count = await select.CountAsync(); var items = await select.Page(page, limit).ToListAsync(); return new { count, items }; } [HttpGet("vs_dapper")] async public Task<object> vs_dapper() { var conn = new SqlConnection("Data Source=.;Integrated Security=True;Initial Catalog=cms;Pooling=true;Max Pool Size=11"); conn.Open(); var count = await conn.ExecuteScalarAsync<int>("SELECT count(1) FROM[dbo].[tag] a"); //conn.Close(); //conn = new SqlConnection("Data Source=.;Integrated Security=True;Initial Catalog=cms;Pooling=true;Max Pool Size=11"); //conn.Open(); var items = await conn.QueryAsync("SELECT TOP 20 a.[id], a.[parent_id], a.[name] FROM[dbo].[tag] a"); conn.Close(); return new { count, items }; }

连接池最大分别为:10,11

使用 apache ab 命令行测试上面两个接口

ab -c 10 -n 1000 -s 6000 测试结果差不多。

-c 100 时,vs_dapper直接挂了,vs_gen没影响(使用了SafeObjectPool)

实践证明ado.net过于暴露,突然的高并发招架不住。

3|0SafeObjectPool

它是一个对象池,可用于控制任何资源紧缺的对象,使用容器化管重复使用提升性能,有序的排队获取,使用完后归还资源。

与ado.net连接池不同的地方,SafeObjectPool 解决池用尽后,再请求不报错,进行排队等待机制,并且适用任何对象不局限于数据库连接对象。

SafeObjectPool 提供可用性检查方法,比如 redisClient 不可用时,所有Get/GetAsync都将报错,直到后台服务检查并恢复状态。

4|0使用方法

Install-Package SafeObjectPool

var pool = new SafeObjectPool.ObjectPool<MemoryStream>(10, () => new MemoryStream(), obj => { if (DateTime.Now.Subtract(obj.LastGetTime).TotalSeconds > 5) { // 对象超过5秒未活动,进行操作 } }); var obj = pool.Get(); //借 pool.Return(obj); //归还 //或者 using 自动归还 using (var obj = pool.Get()) { }

5|0异常

  • 同步获取资源时 pool.Get()

【连接池名称】状态不可用,等待后台检查程序恢复方可使用。

SafeObjectPool.Get 获取超时(10秒),设置 Policy.IsThrowGetTimeoutException 可以避免该异常。

  • 异步获取资源时 pool.GetAsync()

【连接池名称】状态不可用,等待后台检查程序恢复方可使用。

SafeObjectPool.GetAsync 无可用资源且队列过长,Policy.AsyncGetCapacity =10000。

  • 后台服务检查可用性时

CheckAvailable 无法获得资源,Pool: 0/10, Get Wait: 0, GetAsync Wait: 0


6|0扩展现实

6|1SQLServer连接池

查看源码

var pool = new System.Data.SqlClient.SqlConnectionPool("名称", connectionString, 可用时触发的委托, 不可用时触发的委托); var conn = pool.Get(); try { // 使用 ... pool.Return(conn); //正常归还 } catch (Exception ex) { pool.Return(conn, ex); //发生错误时归还 }

6|2MySQL连接池

查看源码

var pool = new MySql.Data.MySqlClient.MySqlConnectionPool("名称", connectionString, 可用时触发的委托, 不可用时触发的委托); var conn = pool.Get(); try { // 使用 ... pool.Return(conn); //正常归还 } catch (Exception ex) { pool.Return(conn, ex); //发生错误时归还 }

6|3PostgreSQL连接池

查看源码

var pool = new Npgsql.NpgsqlConnectionPool("名称", connectionString, 可用时触发的委托, 不可用时触发的委托); var conn = pool.Get(); try { // 使用 ... pool.Return(conn); //正常归还 } catch (Exception ex) { pool.Return(conn, ex); //发生错误时归还 }

7|0结语

本文由 ado.net 连接池,衍生到 SafeObjectPool,基于 SafeObjectPool 现实了 SQLServer连接池、MySQL连接池、PostgreSQL连接池。还有很多连接对象,比如redis client、rpc client、各大消息队列client,都可以封装起来。

谢谢观看,支持开源思想和奉献。

SafeObjectPool github:https://github.com/2881099/SafeObjectPool


__EOF__

本文作者FreeSql & CSRedis
本文链接https://www.cnblogs.com/kellynic/p/9768452.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   nicye  阅读(3007)  评论(5编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· 展开说说关于C#中ORM框架的用法!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
点击右上角即可分享
微信分享提示