接到手这块Atlas 300V 24G的时候我第一反应也是去查它到底算运算加速卡还是别的什么卡。等真正把YOLOv5跑起来又折腾了一阵驱动和模型转换之后才发现网上一堆帖子说得云里雾里。这篇文章就围绕两个高频问题来写Atlas 300V 24G到底是什么类型的卡以及在这个卡上部署YOLO推理的完整链路。实测、踩坑、调优都会覆盖希望能帮正在选型或已经入手这块卡的朋友少走弯路。1. Atlas 300V 24G的真实定位推理加速卡不是训练卡1.1 “是运算加速卡吗”这个问题的标准答案先说结论Atlas 300V 24G是华为昇腾系列的AI推理加速卡不是用来跑训练的计算卡也不是传统意义上的GPU图形卡。它面向的场景是把训练好的模型YOLO、ResNet、Transformer这类部署到数据中心或边缘服务器上做高吞吐、低延迟的推理。很多人会拿它和NVIDIA的T4、A10对比这思路没错但有个关键差异Atlas 300V 24G上没有显示输出接口不能接显示器纯计算设备。它的算力单位不是TFLOPS而是TOPSTera Operations Per Second也就是每秒万亿次整数/低精度浮点运算。昇腾的推理卡主打的INT8算力FP16只是辅助这点和GPU生态用FP16/FP32衡量完全不同。1.2 参数拆解24G显存到底意味着什么Atlas 300V 24G后边的24G指板载内存24GB。这在推理卡里算大容量了T4是16GBA10是24GB所以它是冲着“大模型、多路视频流、大batch推理”去的。从硬件规格来看这块卡采用昇腾310P系列芯片具体型号可以用npu-smi info查看单卡功耗最高75W左右不需要外接供电PCIe供电就够对服务器整机功耗和散热很友好。支持PCIe 4.0 x16接口理论带宽足够喂饱多路视频流。值得一提的是它支持多卡堆叠。一台8卡服务器可以插8张300V相当于一台8路推理整机很多智慧园区、安防、工业质检项目就是这么干的。1.3 和NVIDIA GPU生态的思维差异如果你之前只用过CUDA生态第一次接触Atlas会很不习惯。NVIDIA用nvidia-smi、CUDA、TensorRT昇腾用npu-smi、CANN华为的计算架构、MindSpore/ONNX/ACL。虽然概念一一对应但工具链完全不同。部署YOLO时NVIDIA这边可以直接用TensorRT优化ONNX模型而Atlas这边需要走CANN的ATC工具把ONNX或MindSpore模型转换成昇腾专用的.om格式再通过ACLAscendCL或MindX SDK调用。这条链路不复杂但版本兼容性很容易出问题后面第三节细讲。1.4 选型建议为什么最终选了300V 24G结合项目实际需求来聊选型。当时我们做的是一个智慧工地项目需要同时处理20路1080p视频流做安全帽、反光衣检测单路视频要求不超过150ms延迟。对比了几款卡型号显存典型算力功耗部署难度适用场景Atlas 300I Pro16GB中等INT872W中中等路数视频流Atlas 300V 24G24GB较高INT875W中多路视频流、大batchNVIDIA T416GB65TFLOPS FP1670W低生态成熟通用推理NVIDIA A1024GB31TFLOPS FP16150W低中大模型推理最终选300V 24G的原因很直接一是单卡24G显存能塞下YOLOv5m甚至YOLOv5l的batch 1模型还能同时挂多个模型实例二是功耗低机房改造压力小三是采购成本比A10低不少。缺点也很明显工具链相对封闭网上中文资料少遇到问题只能翻官方文档和查社区。2. 部署环境准备从裸机到识别设备的完整流程2.1 硬件环境与操作系统要求部署之前先确认服务器主板能识别这块卡。Atlas 300V 24G是标准PCIe全高半长卡不挑主板但要注意PCIe槽位供电能力部分老主板PCIe x16槽供电不足会导致卡无法稳定运行。建议用服务器主板或工作站级主板比如超微X11/X12系列、戴尔R750等。操作系统方面官方支持Ubuntu 20.04.5 LTS x86_64、CentOS 7.6/8.2等。强烈建议用Ubuntu 20.04.5 x86_64原因无他内核版本对应驱动包全CANN工具链的预编译版本覆盖最全。如果用CentOS某些内核配置要手动调容易卡在编译内核模块那一步。安装驱动前先做两件事第一确认内核版本执行uname -r第二安装内核头文件否则驱动编译会失败。Ubuntu下命令sudo apt-get update sudo apt-get install -y linux-headers-$(uname -r) gcc make dkms这一步能避免后面驱动安装时“kernel header not found”的尴尬。2.2 驱动与固件安装顺序先固件后驱动别搞反昇腾卡的安装顺序有硬性要求先装固件Firmware再装驱动Driver然后重启。如果先装驱动再升固件驱动加载时会频繁报版本不匹配的错误即使重装驱动也未必能恢复干净。固件和驱动的安装包从华为昇腾社区下载通常叫Ascend-hdk-310p-npu-firmware_x.x.x.run和Ascend-hdk-310p-npu-driver_x.x.x.run。安装命令# 安装固件 chmod x Ascend-hdk-310p-npu-firmware_*.run sudo ./Ascend-hdk-310p-npu-firmware_*.run --full # 安装驱动 chmod x Ascend-hdk-310p-npu-driver_*.run sudo ./Ascend-hdk-310p-npu-driver_*.run --full # 重启服务器 sudo reboot这里有个细节--full参数表示完整安装包括内核模块、工具链等。安装完成后用npu-smi info查看设备状态。2.3 npu-smi info输出怎么看如果你之前习惯nvidia-smi那npu-smi info的字段会让你有亲切感但又不完全一样。关键看这几个npu-smi info输出里重点关注Chip Count / Chip Name确认芯片型号比如Ascend 310P。Temperature正常待机温度在35-50℃之间满载在60-75℃之间超过85℃要检查散热。Hugepages-Usage大页内存使用情况CANN推理依赖大页内存如果为0说明没有配置。Memory Usage板载显存使用率部署后模型会占用一定显存。VersionDriver和Firmware版本号要和CANN工具链要求的版本匹配。配置大页内存这一步很容易漏。CANN的ACL推理默认会申请大页内存作为host侧内存池不配置的话程序会报aclrtMalloc失败或性能极差。建议在/etc/sysctl.conf里加上vm.nr_hugepages 8192 vm.hugepagesz 2MB执行sysctl -p生效。8192个大页对应16GB大页内存够绝大多数推理场景用了。2.4 CANN工具链安装版本匹配是元问题驱动和固件装好之后还要装CANN工具包它是昇腾的计算架构相当于CUDA Toolkit。注意版本一定要和驱动匹配。我当时用的组合是Driver: 24.1.rc1Firmware: 24.1.rc1CANN Toolkit: 7.0.RC1安装CANN Toolkit的命令chmod x Ascend-cann-toolkit_7.0.RC1_linux-x86_64.run sudo ./Ascend-cann-toolkit_7.0.RC1_linux-x86_64.run --full装完后设置环境变量source /usr/local/Ascend/ascend-toolkit/set_env.sh为了省事建议把这行加到~/.bashrc里每次登录终端自动生效。安装完成后执行ascend_install.sh里的验证脚本或者直接npu-smi info确认工具链能识别设备。3. 从PyTorch权重到OM模型YOLO部署的核心链路3.1 为什么非要转成OM模型这个问题我当初也疑惑——既然CANN支持直接加载ONNX为什么还要多一步转OM因为OM是昇腾专用的静态图格式包含了算子调度、内存复用、图优化等编译结果推理时不需要再做图解析和算子选择启动更快、运行更稳定。类比一下ONNX是“源码包”每次运行都要编译解释OM是“编译好的可执行文件”拿到手直接跑。所以ATC转换是部署昇腾的必经之路。3.2 导出ONNX的几个坑opset版本和Resize算子在PyTorch侧导出YOLOv5的ONNX模型官方仓库提供了脚本但有几个地方需要手动确认。第一opset版本。昇腾ATC对ONNX算子支持有版本下限建议opset设为11或13太高太低都可能出问题。导出命令python export.py --weights yolov5s.pt --include onnx --opset 13 --batch-size 1第二动态batch vs 固定batch。ATC支持动态batch但动态shape在昇腾上会带来额外的算子优化限制性能通常不如固定shape。如果业务里batch是固定的强烈建议导出固定batch模型比如--batch-size 1后面推理时用多实例并发来提升吞吐而不是靠动态batch。第三Resize算子的坑。YOLOv5的预处理和后处理中都有Resize操作。导出ONNX时如果模型内部带了nn.Upsample在ATC转换时偶尔会报Resize unsupported错误。解决方案通常是在导出ONNX前把模型的后处理部分剪掉只保留主干输出Resize放到AIPP里做。AIPPAI Preprocessing是昇腾的硬件预处理单元支持在模型输入前完成缩放、归一化、色域转换不占AI Core资源这是昇腾推理卡一个很实用的能力。导出ONNX时还需要注意输出节点命名。ATC转换时要么指定输出节点要么让ATC自动识别。YOLOv5的输出通常是三个尺度的特征图如果直接转ATC会把三个输出都保留但后处理需要你用ACL去解析这三个输出。我建议把三个输出合并成一个大的输出张量或者修改模型只导出指定输出这样后续用ACL推理时处理逻辑简单很多。3.3 ATC转换AIPP配置和关键参数有了ONNX模型下一步就是用ATC转换成OM。我用的命令行大致如下cd /usr/local/Ascend/ascend-toolkit/latest/bin ./atc --model/path/to/yolov5s.onnx \ --framework5 \ --output/path/to/yolov5s \ --soc_versionAscend310P3 \ --input_shapeimages:1,3,640,640 \ --insert_op_confaipp.cfg \ --output_typeFP16 \ --input_formatNCHW几个参数的说明--framework55代表ONNX这是ATC约定的值。--soc_version这个要和你实际芯片型号严格匹配。用npu-smi info查看芯片信息后在官方文档里查对应soc_version。我当时查到的对应关系是310P系列用Ascend310P3但不同批次可能有差异务必以官方文档为准。--insert_op_confaipp.cfg插入AIPP预处理配置。aipp.cfg内容大致如下aipp_op { aipp_mode: static input_format: RGB888_U8 src_image_size_w: 640 src_image_size_h: 640 csc_switch: true rbuv_swap_switch: false matrix_r0c0: 0.00392156862745098 matrix_r0c1: 0 matrix_r0c2: 0 matrix_r1c0: 0 matrix_r1c1: 0.00392156862745098 matrix_r1c2: 0 matrix_r2c0: 0 matrix_r2c1: 0 matrix_r2c2: 0.00392156862745098 output_format: RGB888_U8 }这段配置的意思是把输入图片归一化到0~1之间并切换为RGB顺序。要注意的是YOLOv5官方训练时用RGB归一化除以255这些可以放到AIPP里让硬件代劳host侧拿到原始图片直接喂进去就行省掉CPU上的预处理时间提升整体帧率。如果不需要AIPP可以不加--insert_op_conf但那样输入侧的Resize、归一化都得在host侧手动做多一路内存拷贝延迟更高。3.4 转换失败的常见报错算子不支持怎么办ATC转换过程最让人头疼的就是报错。常见的有几类第一类Unsupported op type: Xxx。这说明ONNX里的某个算子昇腾还不支持。解决办法一是升级CANN版本新版本算子覆盖更全二是回退ONNX中的算子实现比如把Einsum换成MatMulReduceSum把某些激活函数换成Clip三是用自定义算子但那需要写TBE算子工程量大不推荐新手上来就搞。第二类Input shape mismatch。说明ATC参数里的--input_shape和ONNX模型的输入尺寸不一致。用onnx.shape_inference检查一下模型的输入输出维度确认是1,3,640,640还是1,3,416,416。第三类The soc version is not supported。soc_version没写对。有些型号固件版本不同支持的soc_version也会不同。这块只能查官方文档对表没有捷径。我当时卡得最久的是YOLOv7的RepConv算子在ATC转换时出现算子兼容性问题后来改成YOLOv5s就顺畅了。所以如果模型结构太新昇腾那边算子适配还没跟上不妨换个同源但结构老一点的模型比如YOLOv5、YOLOv8的早期版本反而省事。4. 用MindX SDK还是ACL推理两种部署方式的取舍4.1 MindX SDK适合快速搭建pipelineMindX SDK是昇腾的推理应用开发套件核心思想是“插件化”。你用几个现成的插件读图、解码、缩放、推理、后处理串成一条pipeline用配置文件声明就能跑通一个完整的推理服务。我用MindX SDK跑过一个安全帽检测demopipeline配置大致是这样的pipeline: - name: decode type: mxpi_imagedecode - name: resize type: mxpi_imageresize props: resizeWidth: 640 resizeHeight: 640 - name: infer type: mxpi_tensorinfer props: modelPath: /path/to/yolov5s.om postProcessConfigPath: /path/to/pp.json它的优势很明显不需要关心ACL的很多底层细节适合快速把demo跑起来。但问题也在这里pipeline的配置项相当多且文档分散一旦性能不达标或报错排查起来反而更麻烦因为中间层把很多细节封装掉了。4.2 ACL推理更底层的掌控力如果你追求最强性能和精细控制用ACLAscendCL直接写推理代码是正路。ACL的接口风格和CUDA Runtime API有点像核心流程是初始化aclInit、aclrtSetDevice加载模型aclmdlLoadFromFile加载OM文件准备输入输出aclDataBuffer、aclmdlCreateDataset执行推理aclmdlExecute释放资源aclmdlUnload、aclFinalize伪代码示例// 初始化 aclInit(nullptr); aclrtSetDevice(0); // 加载模型 uint32_t modelId; aclmdlLoadFromFile(yolov5s.om, modelId); // 准备输入数据 void *inputBuf nullptr; aclrtMalloc(inputBuf, inputSize, ACL_MEM_MALLOC_NORMAL_ONLY); // ... 将图片数据拷贝到inputBuf // 执行推理 aclmdlExecute(modelId, inputDataset, outputDataset); // 获取输出 // ...这套API你一旦写熟了就会觉得比SDK更可控。比如你想用多线程并发推理、手动管理输入输出内存复用、对接零拷贝视频流ACL都能精细控制MindX SDK则受限于插件实现方式。我的建议是demo验证用MindX SDK正式产品用ACL。原因不复杂SDK的pipeline配置适合快速验证模型效果但生产环境一旦要加多路视频、动态调度、错误重试最后还是需要直接操作ACL才能灵活应对。4.3 推理输出的后处理YOLO从三个输出头到检测框模型推理完拿到的是三个尺度的特征图分别是(1, 255, 80, 80)、(1, 255, 40, 40)、(1, 255, 20, 20)以YOLOv5s、80类为例。后处理需要做解码坐标、过滤低置信度、NMS、映射回原图坐标。如果你用PyTorch做后处理那数据要从NPU拷回CPU有一定的PCIe传输开销。更高效的方式是把解码和NMS写成一个自定义算子塞进OM或者用ACL的aclmdlExecute拿到输出后直接用C实现解码NMS。我们在生产项目里是用C手写了后处理单帧1080p的NMS耗时大约2-3ms完全可接受。需要注意的是昇腾的OM模型输出通常是FP16的转成FP32再算后处理会比较稳妥否则某些yolo解码里的logistic计算在FP16下精度损失会导致检测框抖动。--output_typeFP16还是FP32建议实测对比一下再定。5. 性能实测与调优如何把Atlas 300V 24G榨干5.1 跑通之后的第一轮数据部署好之后我跑了YOLOv5s模型640x640输入的单路RTSP视频流推理拿到一批实测数据配置时延单帧吞吐fps显存占用batch 1CPU预处理22ms约45fps1.8GBbatch 1AIPP预处理16ms约62fps1.8GBbatch 4AIPP预处理28ms整batch约90fps5.2GB从数据能明显看到AIPP带来了接近30%的时延下降而batch 4的吞吐量比batch 1单线程高了不少。所以如果你的业务允许攒批比如视频流抽帧检测batch 4是一个性价比很高的配置。5.2 多路并发实例复用 vs 多线程推理20路视频流要同时跑很多人第一反应是开20个线程每个线程单独加载模型、单独推理。这种做法在Atlas 300V 24G上恰恰是性能杀手。原因有两点第一每个模型实例会独占一部分显存和中资源20个实例光显存开销就上去了还会频繁切换上下文实际吞吐不如预期。第二CANN的ACL本身支持多线程共享一个模型你只需要用一个模型实例让多个线程使用不同的输入输出buffer来并发调用aclmdlExecute。实测下来20路视频流共享一个YOLOv5s模型实例每路约8-10ms推理时延整卡总吞吐能做到接近150fps处理抽帧场景CPU占用也低。具体做法模型加载一次创建多个输入dataset每个线程一个提前分配好内存线程之间用队列传递待处理帧。推理完的结果送回业务线程做后处理。这里的关键点是不要用系统默认的流stream最好每个线程创建自己的stream避免不同线程之间的流同步开销。5.3 大页内存和绑核容易被忽视的细节Atlas推理性能受host侧内存和CPU调度影响挺大。上面提到的vm.nr_hugepages配置如果没有生效推理时aclrtMalloc用的是普通页内存时延会明显上涨尤其在多路并发时更明显。用cat /proc/meminfo | grep HugePages确认一下是否生效。另外如果服务器是多核的建议把推理线程和NPU中断绑定在同一个NUMA节点上减少跨NUMA访问的内存时延。实测中绑核后时延能再降2-3ms。绑核工具用taskset就行taskset -c 4,5,6,7 ./your_infer_app5.4 精度和性能的拉锯FP16与INT8Atlas 300V 24G的INT8算力是FP16的好几倍理论上走INT8能显著提升吞吐。但INT8量化需要准备校准集量化后的精度损失因模型和数据集而异。我在YOLOv5s上做过一轮INT8量化实验用的是CANN自带的AMCTAscend Model Compression Toolkit做静态量化校准集选了500张工地图片。结果mAP从0.872降到0.841降了约3.5个点但吞吐提升了近90%。在安全帽检测这类对精度要求不太苛刻的业务里INT8完全够用但如果是火灾烟雾检测这种误报代价高的场景建议还是用FP16稳一点。量化的引入会让部署复杂度上一个台阶如果你是第一次用Atlas部署YOLO建议先FP16跑通后续再根据实际精度余量决定要不要上INT8。6. 高频故障排查记录这些坑我替你踩过了6.1 驱动装完npu-smi里看不到卡这个问题我遇到过两次。第一次是主板BIOS里没开启PCIe 4.0卡降级工作在PCIe 3.0 x8状态下npu-smi info能识别但速率异常。第二次是PCIe槽位接触不良重新插拔后解决。如果npu-smi info直接报No device found按这个顺序排查是否安装了匹配的固件和驱动版本用dmesg | grep -i npu查看内核日志。内核模块是否加载成功执行lsmod | grep drv_pcie如果没有输出说明驱动加载失败。是否被系统识别执行lspci | grep -i Huawei正常能看到类似Huawei Technologies Co., Ltd. Device的设备。BIOS里是否禁用了PCIe设备或者插槽被其他设备占用。6.2 ATC转换时报错找不到vgg16_AI_Fusion etc这是我踩得比较深的一个坑。ATC会加载一些预置的融合规则和算子库有时候环境变量ASCEND_OPP_PATH没有设置就会报类似parser op failed、找不到算子库的错误。解决方法是确认CANN的set_env.sh已经source过并且在当前shell里检查echo $ASCEND_OPP_PATH正常情况下应该指向/usr/local/Ascend/ascend-toolkit/latest/opp。如果这个变量为空说明环境没配好重新source一下即可。6.3 推理时显存越占越多最后OOM运行一段时间后npu-smi info显示显存占用率持续上涨直到aclrtMalloc返回内存不足。这个通常不是NPU显存泄漏而是host侧内存或大页内存泄漏。重点排查后处理代码里有没有及时释放从NPU拷回的特征数据输入输出dataset是否每帧都重复创建而没有销毁是否有线程创建了stream却没有销毁。规范做法是初始化时把所有dataset、buffer、stream一次性创建好整个生命周期内复用直到退出时统一释放。这样不仅不易泄漏还能省掉每帧的内存分配开销性能也会好一些。6.4 OpenCV读RTSP流需要额外编译如果你直接用OpenCV的VideoCapture读RTSP流而编译OpenCV时没有带FFmpeg会报Could not find a writer或者根本无法打开RTSP。建议使用带FFmpeg支持的OpenCV或者装opencv-python-headless预编译版自带FFmpeg省去源码编译的折腾。另外多路RTSP流解码也非常吃CPU如果服务器CPU核数不够20路1080p解码会把CPU打满。实测用Intel 8380双路20路1080p硬解码加YOLOv5s推理CPU占用约45%勉强能跑。如果CPU吃紧可以把视频解码也丢到昇腾卡AIPP里但配置会更复杂建议先保证CPU余量。6.5 多卡场景的泥潭主卡和从卡识别如果有两张卡npu-smi info会列出两张卡但程序默认只会用device 0。如果你指定device 1需要在程序里先aclrtSetDevice(1)。多卡场景下还有一个容易忽略的问题两卡之间P2P通信。昇腾卡之间不像NVIDIA那样支持NVLink跨卡数据交换要通过PCIe带宽有限。如果业务需要多卡协同处理同一路视频建议不要频繁跨卡传数据尽量按卡分业务流。7. 最后分享一点实际体会这段时间用下来我觉得Atlas 300V 24G这个卡定位很清晰它就是为大规模推理业务准备的。它的优势在于单卡功耗低、显存大、INT8吞吐高适合多路视频流、大批量图片处理这类任务缺点在于学习曲线陡CANN工具链的文档质量和社区生态离CUDA还有明显距离。如果你不是非昇腾不可且有大量现成的CUDA代码要部署靠近NVIDIA生态会更顺。但如果你恰好需要国产化替代、关注边缘部署的能效比或者想规避依赖单一GPU厂商的风险Atlas 300V 24G完全值得一试。它的坑虽然多但一旦把工具链摸熟稳定性和性能都相当能打。按我踩坑的经验给新上手的人一句实在建议先照着官方文档把环境装好拿一个简单的resnet50做环境验证再去碰YOLO这类复杂模型能省很多不必要的排查时间。
企业数字化 ERP 产品动态
相关推荐
短信轰炸防御实战:从业务逻辑到运营商协同的三层加固 1. 这不是“技术揭秘”,而是安全防线的实战拆解“短信轰炸”这个词最近在社交平台和社区讨论里频繁出现,但很多人一听到“揭秘”,下意识就往“黑产技术教程”或“黑客工具教学”方向联想——这恰恰是最大的认知误区。我做网络安全一线支撑工作… · 2026/9/25 5:12:46
cuDF 错误处理体系全解:libcudf 异常类型、CUDF_EXPECTS 断言宏与错误码机制 数据分析数据工程机器学习 【免费下载链接】cudf cuDF - GPU DataFrame Library 项目地址: https://gitcode.com/gh_mirrors/cu/cudf 点击查看 免费下载 cuDF(GPU DataFrame Library)的 libcudf 底层实现需要同时面对宿主端(hos… · 2026/9/25 5:39:00
Atlas OS Xbox 登录 0x89235107 修复指南:三步修复找回 Game Pass 登录 Atlas OS Xbox 登录 0x89235107 修复指南:三步修复找回 Game Pass 登录 【免费下载链接】Atlas 🚀 An open and lightweight modification to Windows, designed to optimize performance, privacy and usability. 项目地址: https://gitcode.com/GitH… · 2026/9/25 5:39:00
Buildah v0.12 版本特性全解析:从认证参数到容器镜像管理的改进清单 云原生 【免费下载链接】buildah A tool that facilitates building OCI images. 项目地址: https://gitcode.com/gh_mirrors/bu/buildah 点击查看 免费下载 Buildah 是一个无需守护进程(daemon)即可构建 OCI 镜像的容器构建工具。本篇文章以… · 2026/9/25 5:39:00
工业大模型落地实战:轻量化视觉AI如何省下每班27分钟 1. 这不是“AI喊口号”,而是产线工人每天多省27分钟的真实账本华泰电子团队去年跑通的这套“AI大模型工业”落地路径,和市面上90%的PPT方案有本质区别——它不讲“赋能”“生态”“范式”,只算一笔硬账:某汽车零部件厂的质检工位&… · 2026/9/25 5:39:00
Atlas 300V 24G部署YOLO全指南:从ONNX转OM到ACL推理 最近后台收到好几个提问,内容高度一致:Atlas 300V 24G到底是不是一张能拿来部署YOLO的运算加速卡?有人把它当成普通显卡来插,有人拿它跑PyTorch直接报错,还有人纠结24G显存是不是能“无脑堆模型”。这类问题在安防、边… · 2026/9/25 5:38:54
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37