C#物联网接收端架构:SQLite+EF6如何扛住数万设备高并发接入
看到一批又一批的轻量级高并发物联网服务器接收程序源码时我第一反应是先愣一下——EF6加SQLite这组合怎么看都像桌面软件的配置标题却写着承接数万设备。高并发三个字放在Web后端大家第一反应是Redis、消息队列、分库分表放在IoT场景怎么就变成了SQLite这种单文件数据库直到我连续做了几个物联网接收端的项目才明白这个搭配一点儿都不违和。它真正解决的是边缘计算、中小规模设备接入平台、毕设级物联网系统中用最少资源扛最多连接的诉求而实现的关键全在于接收程序的架构设计而不是堆机器。这篇文章我把这类源码项目背后的完整设计思路拆开讲一遍设备上报的高并发到底是什么模型为什么SQLite在这里能扛得住EF6在其中扮演什么角色以及实际部署中那些文档里不会写的坑。适合正在改造成熟物联网源码做二次开发的人也适合准备用C#自研设备接入层、又不想一上来就引入MySQL加Redis这些重型组件的团队。1. 先想清楚几万设备并发的是哪一种高并发很多人在看到标题的瞬间就进入Web并发思维觉得一万个设备就是一万个请求同时打过来SQLite单文件数据库凭什么扛住。这个直觉是错的。物联网高并发和网站高并发在流量模型上是两码事压力值要重新算。1.1 设备上报的真实压力模型网站高并发是大量用户随时点击请求之间没有固定节奏峰值可能在某一秒集中爆发。物联网设备不一样传感器节点、智能硬件、充电桩这类终端绝大多数是按照固定周期上报数据的可能每10秒一条每30秒一条甚至每分钟一条。它们先建立TCP长连接然后按自己的节奏往服务端推消息。真实计算方式不是在线设备数并发请求数而是每秒上报条数设备数除以上报周期。1万台设备每30秒上报一次平均每秒约333条。2万台设备每10秒上报一次平均每秒约2000条。5万台设备每5秒上报一次平均每秒约1万条。也就是说标题说的数万设备如果控制好上报周期服务器的实际写压力大概率在每秒几百到几千条记录之间。这个量级对SQLite来说完全属于能力范围之内前提是写入方式正确。真正的考验不在数据库而在网络层能不能同时维持几万条活的TCP连接。1.2 SQLite的短板不在读多在写锁SQLite被诟病高并发最核心的原因是它同一时刻只允许一个写事务多个进程或线程同时写会撞上锁。Web应用是天然多写入者的场景服务器上一堆线程各自执行INSERT大家抢同一个库文件SQLite当然成了瓶颈。但物联网接收程序可以设计成只有一个人写库。网络层接收数据后不直接操作数据库而是先丢进内存队列由后台一个独立写入线程做合并批量提交。这样SQLite面对的从来不是每秒几千个小事务而是每几百毫秒一个大事务锁竞争被降到了最低。一个类比是SQLite像只有一个窗口的银行柜台普通场景下所有人都挤在窗口前必然拥堵但如果门口有个工作人员把客户排好队攒够一批再引导进去统一办理这个柜台完全有能力消化几万人的业务量。WAL模式还让这个模型更顺滑。开启WAL后读操作和写操作不再互相阻塞写事务也只是追加到WAL日志文件末尾只有执行checkpoint时才把数据合回主数据库文件这对持续写入型场景友好得多。1.3 EF6在这里只是个工具人整个接收程序里真正决定并发上限的是网络层模型和写入队列设计EF6只负责把对象映射到SQLite表再执行批量落库。EF6性能确实不算极致但在每秒几千条、批量事务提交的范围内毫无压力。它存在的意义是让开发速度快模型清晰后续改字段加表都方便。不要在EF6层面做逐条SaveChanges那是把性能拱手让出去。2. 接收链路分层从TCP连接到SQLite落库要拆成三层拿到这类源码先把接收链路在脑子里拆成三层网络接入层、协议解析层、存储层。三层职责不能混在一起否则并发一上来调试会让人崩溃。2.1 网络接入层用异步Socket扛长连接Windows平台下.NET做高并发TCP接入首选SocketAsyncEventArgs配合IO完成端口IOCP这是Windows内核级异步I/O机制线程不阻塞在Recv上而是等内核通知数据到达。连接数上来之后线程池不会被几千个等待中的Socket拖垮。ASP.NET Core的Kestrel本身也支持自定义TCP中间件能省掉很多底层管道代码两种方案都成立。长连接数量的内存估算其实不高。每个TCP连接在服务端大概占用几十KB的缓存一台2核4G的云服务器光维持连接不上报数据就能挂两万条以上。瓶颈往往出现在业务数据处理上只要每条消息的处理不出现阻塞调用比如不在网络回调里同步写库、不发阻塞HTTP请求连接数不是问题。核心接入流程一般是下面这样接收Socket - 异步Read - 缓冲池 - 拆包解析 - Channel写入队列 ^ 粘包半包处理很多高性能网络库内部还有发送队列和背压控制防止某个连接写入过慢拖垮全局。2.2 粘包半包必须认真处理的时间线设备端发数据通常是TCP流式传输不存在天然的消息边界。服务端一次Read读到的字节可能只包含一条消息的一半也可能包含两条甚至三条完整消息。如果不做边界处理解析结果必然是错乱的。这个问题我见过太多次尤其是从串口转网络的设备过来的数据包之间没有严格间隔时最容易出问题。常规做法是在协议里加一个消息头比如4字节魔数加2字节长度再加2字节CRC。服务端先把数据放进缓冲区不断检查是否凑够了一个完整帧凑够再切割出来交给解析层。用C#写时要注意避免在解析中出现额外分配。缓冲区建议用统一的byte[]池比如ArrayPool 避免每来一条消息就new一个byte[]否则GC压力在每秒上千条消息时非常明显。完整的拆包逻辑大致是这样while (缓冲区内数据 消息头长度) { 读取消息长度字段len; if (缓冲区内数据 len) { 等待后续数据到达; break; } 从缓冲区切出len字节作为一条完整消息; 调用解析层处理; }2.3 心跳、死连接与设备侧的重连策略长连接场景下如何发现设备掉线是个绕不开的问题。物联网设备挂在弱网环境断网后TCP连接可能半开即连接状态看上去还在实际设备已经失联。服务端需要定期检查活跃时间比如超过60秒没有任何消息的TCP连接服务端主动Close。服务端返回心跳响应有两种策略。一种是设备发什么回什么简单直接另一种是定义独立的心跳消息类型收到后回一个固定ACK。推荐后者因为设备端可以据此判断链路是否完全正常。设备侧的重连同样要讲究。如果一万台设备同时掉线又同时以同样的间隔重连服务器就是典型的惊群现象可能直接把服务端打挂。实践做法是设备端加上指数退避第一次断开等2秒重试第二次等4秒最久到60秒并且重连时间点加一点随机扰动。规范里的退避逻辑值得直接借鉴。3. SQLite加EF6的具体调优单写者、批量提交、合理索引三层链路里存储层决定最终吞吐量。SQLite和EF6的组合如果调优得当跑每秒几千条写入是稳定的如果调优失当几千条就能卡住服务。3.1 打开WAL改掉同步模式SQLite默认的journal模式是DELETE或TRUNCATE每提交一个写事务都要反复写主数据库文件磁盘I/O开销大。使用WAL模式后写事务变成顺序追加到WAL文件commit时只需要把少量数据fsync到WAL文件即可整体磁盘压力大幅下降。C#程序连接SQLite后建议在初始化连接时执行一组PRAGMAPRAGMA journal_modeWAL; PRAGMA synchronousNORMAL; PRAGMA busy_timeout5000; PRAGMA temp_storeMEMORY;synchronous设置为NORMAL在WAL模式下即使系统崩溃最坏情况是丢失最近一小段已提交事务但数据库文件不会损坏。这对物联网场景是可以接受的因为设备侧往往有重发机制。有个容易被忽略的细节WAL模式下会额外产生-wal和-shm两个文件部署时不要只备份主db文件需要把两个文件一起处理迁移时同样如此。3.2 EF6写库用批量代替逐条调教EF6的DbContext不是线程安全对象绝不能在多个线程间共享同一个实例。正确姿势是每个工作单元创建新的DbContext用完即释放。在高并发接收程序中这个工作单元最好就是一批写入。最反性能的写法是在网络回调里做context.DeviceData.Add(entity); context.SaveChanges();。每条数据一次事务每秒几千条消息时数据库会死得很惨。正确做法是收集一段时间内累积的实体然后一次性AddRange在单个事务里SaveChanges。核心批量写入代码框架大致如下public async Task BulkInsertAsync(ListDeviceData entities) { using (var context new DeviceDbContext()) { context.DeviceDatas.AddRange(entities); await context.SaveChangesAsync(); } }这里的关键是每个批次只调用一次SaveChangesEF6会把这一批实体组装成一条批量INSERT语句配合SQLite的事务提交性能有数量级的提升。如果追求极致也可以引入EntityFramework.BulkInsert这类第三方扩展库能再压掉一部分EF6的表达式生成开销但先做好基础批量提交已经能覆盖绝大多数场景。3.3 索引是双刃剑NoTracking是标配SQLite单表插入很快但如果表上有过多索引插入时的索引维护成本也会累加。物联网场景最常用的查询维度无非是设备ID加时间范围那就只给这两个字段建索引其余不要为了以防万一乱建。日志型数据的表索引越少写入越轻快。EF6做查询时默认会启动ChangeTracker把查询出来的实体放进上下文跟踪缓存这在只读场景下是纯浪费。给查询加上AsNoTracking()让EF只读不跟踪内存和性能都能改善。这一行代码在很多源码里根本没写但它确实值得加。4. 削峰填谷写入队列和批量落库的核心设计最考验这类接收程序水平的部分其实是网络层和存储层之间那一段数据通道。它决定了SQLite是进入天堂还是地狱。4.1 队列选型用Channel而不是裸List加锁写入队列的核心作用是缓冲上报峰值。设备上报虽然平均频率固定但很多设备会整点同步或者出现集中重连后的集中上报瞬时压力可能达到平均值的五到十倍。C#里现在首选System.Threading.Channels开箱即用的异步生产者-消费者管道。Channel支持有界容量满了以后可以选择让生产者等待也可以选择丢新数据或丢老数据。物联网场景下数据宁可丢也不能阻塞网络层因为阻塞会让TCP连接缓冲区堆积引发连锁超时。所以推荐设置一个有界容量比如10万条满员时标记丢弃并记录日志var options new BoundedChannelOptions(100000) { FullMode BoundedChannelFullMode.DropWrite, SingleReader true }; var channel Channel.CreateBoundedDeviceData(options);设备数据本身就带时间戳丢了一条旧数据不影响后续链路比起让服务端全部阻塞强得多。为什么要强调SingleReader因为写入SQLite的线程只保留一个避免多线程写库互相踩锁。生产者可以有无数个消费者只有一个这也正好呼应SQLite的单写者模型。4.2 批量策略按时间和数量双阈值触发消费者线程不能一直空转等数据也不能攒到天荒地老不落库。实践中用两个条件取先出现的那个通道中累积数量达到500条立即触发批量写入距离上一次写入超过2秒即使数量不够也把现有数据写入。这两条合在一起就是空闲时段数据能尽快落库繁忙时段数据能攒成大事务批量提交。写入频率被控制在一个合适区间内SQLite的提交开销就被均摊了。后台消费的简化逻辑长这样var buffer new ListDeviceData(capacity: 500); await foreach (var item in channel.Reader.ReadAllAsync()) { buffer.Add(item); if (buffer.Count 500 || sw.ElapsedMilliseconds 2000) { await BulkInsertAsync(buffer); buffer.Clear(); sw.Restart(); } }每次提交的事务越大每条数据的均摊开销就越小但也不能无限大单批次5000条以上时内存和事务时长会变成新瓶颈建议控制在500到2000条之间具体数值压测调优。4.3 崩溃恢复与幂等设计批量写入意味着进程崩溃时会丢一批未写库的数据。要接受这个事实不要试图在服务端把数据保证做到100%物联网的端到端可靠是靠设备侧重发来解决的。接收程序只需要保证崩溃后能快速重启重启后能继续接收已写库的数据不丢失。那如何避免重复写入造成的数据混乱让设备消息携带自增序号或消息ID服务端表对设备ID消息ID建唯一索引重复写入时SQLite会报唯一约束冲突程序捕获后跳过即可。这招在设备重发场景下特别好用能天然防重。另外时间戳问题要认真处理。设备时钟不可信强烈建议服务端在接收时生成自己的接收时间字段。如果你的业务逻辑对时间敏感比如需要按时间窗口统计一定要用服务器接收时间做基准设备时间单独存一个字段仅供参考。5. 从压测结果反推容量5000到50000连接的真实差距所有设计最终都要用数字说话。我按1万设备、每10秒上报一次、每条消息约200字节来做个模拟每秒约1000条写入每条记录包含设备ID、接收时间、数据体。SQLite批量提交模式下单事务写入500条大约耗时十几毫秒到几十毫秒每秒需要两个批次处理器占用很低2核4G服务器跑得很轻松。设备端的连接支撑力在异步模型下也不是问题。用自定义压测脚本模拟1万连接服务端每秒能接收1000条消息CPU稳定在15%到25%之间内存占用约1到2GB。把上报频率调到每秒1次即1万条每秒数据库批处理时间开始成为主关注点单事务写入2000条可能需要200到400毫秒此时每秒得处理五个批次CPU也来到50%上下但磁盘换成SSD后依然能跑动。再往上模拟5万连接每5秒上报一次也就是每秒1万条此时并发线程数量和GC开始变得敏感需要调整缓冲区池加大Channel容量并考虑拆分为多个接收实例分摊。一组直观的容量对照如下连接数上报周期每秒写入条数SQLite批处理策略服务器参考配置1万30秒333500条一批2核4G1万10秒1000500条一批2核4G3万10秒30001000条一批4核8G5万5秒100002000条一批4核8G/SSD这里表格只做参考真正上线前一定要压测自己的协议和机器。现实里设备不是均匀上报的整点跳变是常态所以把容量评估打个五折后预留是稳妥的做法。压测时还有一个隐藏瓶颈经常被忽略文件句柄数。Windows上默认单进程TCP连接数受端口范围和非物理内存限制影响生产环境要在操作系统层面放开限制。Linux部署的话也要记着调高nofile否则连接数到几千就报too many open files数据库再快也白搭。6. 生产环境里躲不掉的几个坑理论设计再顺真跑起来之后还是会踩坑。把几个高频问题列出来遇到了能少走很多弯路。6.1 DbContext千万不能静态共享这是EF6最常见的翻车点。DbContext内部有变更跟踪器不是线程安全的多线程同时调用就可能抛出Collection was modified或者更随机的异常。写一个静态容器存DbContext在控制台程序里跑没问题放到高并发网络服务里跑几小时之内必崩。正确做法是每个批量任务new一个DbContext用完using释放底层连接池会复用数据库连接创建代价没有想象中高。6.2 SQLite文件别放网络盘别让多进程打开SQLite在高并发场景下对文件锁非常敏感。很多人图省事把db文件放到NAS或者网络共享路径结果发现一到高负载就频繁报database is locked。这不是SQLite不行是网络文件系统的锁机制根本不支持SQLite需要的粒度。数据库文件必须放在本地物理磁盘或SSD而且不要在同一台机器上挂多个进程同时打开同一个文件即使这些进程只是读也会带来锁协商的额外开销。6.3 SQLite文件加密与备份SQLite数据库默认不加密db文件拷走就能看内容这在很多项目里存在安全隐患。SQLite官方有付费的SEE方案免费实现也有第三方Extension可选。但加密会在每次读写时增加加解密CPU开销IO写入条数大时性能下降明显取舍需要业务方自己拿捏。如果业务可以接受更稳的做法是在应用层对敏感字段做加密表结构本身不加密兼顾性能和安全。备份也值得多说一句。SQLite支持在线备份接口但最简单可靠的方案是在业务低峰期用sqlite3命令做一次一致性备份或者直接停写瞬间复制db和wal文件。不建议在写入高峰期直接复制db文件因为WAL模式下主库文件可能并未包含最新数据光复制主文件会导致丢数据。6.4 往上再走的扩展路径Sqlite方案的价值在轻量接入但它不是终点。很多项目是先接收落到SQLite再由另一个后台任务定时把SQLite里的数据批量出库转投到MySQL、PostgreSQL或者时序数据库做长期分析。接收程序保持轻量数据管道后台做分发这是很务实的分层。如果公司已经有时序数据库基础设施也可以让接收程序直接把数据同时发给时序库SQLite只做本地缓存与断网续传。用SQLite做IoT接收端的核心价值是把复杂度控制在最小范围内。设备接入、数据落库、快速上线不需要运维Redis不需要管理消息队列不需要采购大数据库实例——一台普通云服务器就能扛住数万设备的接入压力。等量级真的大到SQLite扛不住再往后端加时序库和应用层削峰也是平滑演进而不是推倒重来。最后分享一个实际体会这类接收程序的性能隐患90%不在数据库而在代码里阻塞了网络线程。凡是遇到莫名卡顿、断连、CPU飙高先查网络回调里有没有同步IO查解析层有没有不自控的分配查队列有没有满通常都比怀疑SQLite更接近真相。轻量方案有小范围的稳妥架构越简单越要把每一行代码放在对的位置上。

相关新闻

LightGBM增益计算原理与四层嵌套机制解析

LightGBM增益计算原理与四层嵌套机制解析

1. 这不是“看懂公式”就够的——LightGBM增益计算到底在算什么LightGBM源码如何计算增益——这个标题乍一看是技术细节问题,但实际踩进坑里的人很快会发现:光盯着split_gain.hpp里那几行C代码,根本没法真正理解模型为什么这么分、分得对不对…

2026/10/13 6:27:47 阅读更多 →
SQLFlow 自定义模型指南:用 Python 定义可被 SQL 调用的深度学习模型

SQLFlow 自定义模型指南:用 Python 定义可被 SQL 调用的深度学习模型

人工智能机器学习后端编译器 【免费下载链接】sqlflow Brings SQL and AI together. 项目地址: https://gitcode.com/gh_mirrors/sq/sqlflow 点击查看 免费下载 导读 SQLFlow 的核心能力是让 SQL 程序直接调用用 Python 定义的深度学习模型——用户只需在 SQL 中书…

2026/10/13 6:27:47 阅读更多 →
5分钟搞定B站API:开发者必备的实战指南

5分钟搞定B站API:开发者必备的实战指南

5分钟搞定B站API:开发者必备的实战指南 B站作为中国最大的弹幕视频网站,拥有海量的内容和活跃的社区,其API为开发者提供了丰富的开发可能性。无论你是想分析视频数据、获取弹幕信息,还是构建自动化工具,掌握B站API都能…

2026/10/13 6:27:47 阅读更多 →

最新新闻

Win7离线OCR工具:PaddleOCR-json免Python部署实战

Win7离线OCR工具:PaddleOCR-json免Python部署实战

简介:win7-x64-PaddleOCR-json.zip是面向Windows 7 64位系统的PaddleOCR部署压缩包,适用于需要在旧版平台快速搭建文字识别能力、并通过JSON格式获取结构化结果的开发者和运维人员。包内共64个文件,总体积约126.19MB。其中dll动态库用于支撑推…

2026/10/13 7:13:58 阅读更多 →
AI应用上下文管理实战:分层压缩方案详解

AI应用上下文管理实战:分层压缩方案详解

我做过一个内部的智能客服项目,上线三个月后收到最多的用户反馈不是"回答不准",而是"它怎么又把我说过的话忘了"。用户在第十分钟重新提起自己五分钟前强调过的产品型号时,模型一本正经地给出了另一款产品的介绍。查日志…

2026/10/13 7:13:58 阅读更多 →
LSTM+Attention时序预测实战:从原理到PyTorch落地

LSTM+Attention时序预测实战:从原理到PyTorch落地

1. 从"预测"这个词说起:为什么LSTM加Attention成了时序任务里的常驻组合做时序预测的人大概都有过这样的经历:拿到一批带时间戳的数据,第一反应是上ARIMA或者简单移动平均,跑出来的结果在平稳段看着还行,一到…

2026/10/13 7:13:58 阅读更多 →
扣子3.0零代码搭建AI智能体:工作流与多Agent协作实战

扣子3.0零代码搭建AI智能体:工作流与多Agent协作实战

扣子 3.0 这个版本,最核心的变化就是把“搭建 AI 智能体”这件事,从写代码变成了搭积木。你不需要懂 Python,不需要本地显卡,打开浏览器登录就能开始做。这篇文章会带你从零开始,走完一个完整的智能体搭建流程&#xf…

2026/10/13 7:13:58 阅读更多 →
HuggingFace英译中模型迁移ONNX:导出、推理与量化部署全攻略

HuggingFace英译中模型迁移ONNX:导出、推理与量化部署全攻略

最近把一个托管在 HuggingFace 上的英译中模型真正搬进了生产环境,折腾了一阵子之后,总算把完整的导出、推理、优化流程打通了。这篇内容就是从那个项目里整理出来的,全程聚焦一件事:如何把一个 HuggingFace 上的英译中模型迁移到…

2026/10/13 7:13:58 阅读更多 →
零基础AI漫剧量产:12模块工业化流水线实战

零基础AI漫剧量产:12模块工业化流水线实战

1. 这不是“AI绘画课”,而是一套可批量交付的漫剧工业化流水线“零基础 AI 漫剧智能量产创作营”——光看标题,很多人第一反应是:又一个教Stable Diffusion换脸、用Runway生成动图的速成班?我最初也这么想。直到去年参与某高校数字…

2026/10/13 7:12:57 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 14:48:49 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →