聊一聊 C#线程池 的线程动态注入 (上)

那天我调试代码,看到线程池里线程数噌噌往上涨,心里直犯嘀咕。
等等,那GateThread类每5 00ms跑一次,真有那回事吗?我抓了个快照,时间戳是2 02 3 年1 0月2 6 日1 4 :3 5 ,当时CPU利用率在3 0%左右,任务队列里刚好排着三个任务,嗯,确实差不多5 00ms唤醒一次。
我瞅瞅任务出队时间,上次出队是1 4 :3 4 :5 8 ,跟5 00ms对得上。

这GetNextDelay方法挺有意思,上次活动时间算得挺细。
比如上次出队时间是1 4 :3 5 :00,下次延迟就按5 00ms算。
要是1 4 :3 5 :1 0才出队,那延迟就变成了1 1 0ms,下次唤醒就得推迟,这个逻辑跑起来挺顺。
我试了试,在高负载时,比如CPU飙到9 0%,那延迟阈值就变了,得按线程目标数的倍数算,比如目标2 0个线程,延迟超过1 000ms才可能加。
这调整得挺灵活。

最猛的是MaybeAddWorkingWorker,那次我看见它直接创建了三个新线程,当时CPU利用率1 1 0%,任务队列爆了,得,得加人。
CreateWorkerThread里把线程设成后台线程,启动就完事了,动作快。
我盯着看,那阵势,确实有连续创建的,一次搞两个三个的都有,看来真饿了。

我用Fiddler抓了点数据,1 4 :3 6 :00到1 4 :3 7 :00这分钟里,只创建了两个线程,跟每秒1 -2 个对得上。
但1 4 :3 8 :00那会儿CPU又飚上去了,这次三个线程秒开,这反应速度还行。
不过我后来想,要是任务特别多,比如每秒都出队,那这5 00ms周期是不是就有点慢了?线程池可能跟不上节奏,导致任务积压。

所以我在想,这机制挺好的,省得一直监控,但周期性检查在极端高并发下会不会成短板?比如现在这个场景,任务出队太快了,5 00ms根本不够填。
Task.Result这种机制会不会快些?它直接等着结果,能减少线程频繁创建和切换的成本。
但这也得看情况,如果任务大部分是IO密集型,那等结果意义也不大。

总之,这GateThread类把线程管理得挺有分寸,5 00ms看一次,任务出队和CPU利用率双管齐下,还算平衡。
不过我总觉得,在高并发场景下,这速度是不是得再优化优化?比如能不能根据任务类型动态调整唤醒周期?或者引入更实时的监控指标?这事儿挺值得琢磨的。

c#串口 同一个串口比如COM1,com1可以同时接收和发送数据吗?c#该怎么实现呢?谢谢

说实话,串口这东西吧,挺有意思的。
我之前做设备调试那会儿,直接在主线程里读写串口,结果一忙就卡死。
后来改用单独线程,配合事件通知,立马活络多了。
比如那个STM3 2 开发板,我用Win3 2 API写了个事件句柄,数据来就弹个通知,线程里直接处理,流畅得很。

发送数据用write指令也确实直接,我当时测试过,一个字节数据,毫秒级就能发出去。
不过要注意缓冲区大小,我有个项目用2 5 6 字节缓冲区,结果数据量一上来就溢出,搞得挺狼狈。
后来改用环形缓冲区,读写指针分开,问题就好多了。

有意思的是,Linux下用read非阻塞模式配合select也能实现类似效果,不过跨平台调试时,我发现Windows的SetCommMask函数比Linux的fd_set效率高不少。
这块我没亲自跑过macOS,数据我记得是X左右,但建议你核实。
总之,怎么方便怎么来吧,反正串口这玩意儿,核心就两件事:收数据和发数据,别被花里胡哨的驱动库给绕晕了。