1. 入手Atlas 300V 24G前先把“运算加速卡”这几个字搞清楚最近好几个朋友拿着一块Atlas 300V 24G问我同一个问题这卡到底是不是运算加速卡怎么跟平时见的显卡长得不太一样也没显示输出口能不能直接插到台式机上跑YOLO先说结论它确实是运算加速卡但“运算加速”这四个字得拆开看。它加速的不是图形渲染也不是通用计算里那种包打天下的CUDA生态而是专门为神经网络推理设计的一套异构计算单元。说白了它是一张AI推理卡不是一张“显卡”也不是一张拿来挖矿或者跑科学计算那种通用加速卡。整卡高度约等于一条加长的显卡单槽位设计功耗标称70W上下24G显存版用的是HBM接口是PCIe 3.0 x16供电只需要外接一个8pin。单从硬件规格上看它确实是个“运算加速卡”的形态但真正让它值钱的是卡上的AI Core。我最初拿到这块卡时第一反应也是先查它算不算“运算加速卡”因为这个名字太有迷惑性。后来在昇腾社区翻了不少资料又跑了几个实际模型才算把定位摸清楚。如果你是在网上搜“atlas 300v 24g 是运算加速卡吗”搜到这篇那我可以直接给你一个准话它是加速卡而且是专门加速深度学习推理的卡不是用来训练大模型的也不是用来跑CUDA程序的。它的定位是给已经训练好的模型做线上推理把模型跑得快、跑得稳、跑得省电。1.1 它到底加速的是什么运算要理解Atlas 300V 24G的定位得先搞清楚AI推理和AI训练是两种完全不同的“运算”。训练的过程像是一个学生学习做题需要反复迭代、调整参数计算密集度极高而且对精度要求苛刻通常用FP32甚至FP16混合精度来做。推理的过程更像是学生已经学成毕业在考场上限时答题模型权重不再更新只需要对输入数据做一次前向计算速度和延迟才是第一优先级。Atlas 300V 24G上的AI Core就是专门为这种“前向计算”设计的。它内部有大量的矩阵乘法和向量计算单元并且针对INT8做了深度优化。官方标称的INT8算力能做到140 TOPS左右这个数字在同类单卡里其实相当能打。但要注意这是INT8的算力FP16大概只有70 TFLOPS左右FP32就更弱了。这就决定了它的使用方式训练好的模型经过量化或精度校准后转成INT8模型推理速度才有质的飞跃。我拿YOLOv5s跑过一次对比测试同样的输入尺寸640x640纯FP32的OM模型跑下来大概需要12毫秒左右转成INT8之后可以压到4到5毫秒。这个差距就是AI Core里INT8算力堆出来的结果。如果你手头的模型对精度极度敏感不能量化那这块卡的优势就打折扣得考虑FP16甚至更高精度的硬件。1.2 和GPU推理卡的核心差异很多人习惯拿它和NVIDIA的T4、A10做比较因为大家都插PCIe都做推理。但抛开算力看架构差异非常明显。GPU的推理能力是“通用计算单元附带出来的技能”它的核心还是CUDA Core那一套什么都能算但什么都不是最专的。Atlas 300V 24G则相反它从设计之初就砍掉了图形渲染、通用并行计算这些负担把所有晶体管都堆在AI Core上。这带来的直接好处是能效比极高70W功耗就能跑出接近甚至超过某些150W级别GPU推理卡的INT8算力。在一个机箱里插满四张、八张卡做推理服务时整机的功耗和散热压力会小很多。另外非常关键的一点是Atlas 300V 24G的显存是24G。对于推理场景来说大显存意味着能塞下更大的模型或者同一张卡上同时跑多个模型实例。我做过多路视频流分析一张卡上并行跑4个YOLOv5s实例每个实例处理一路1080p视频显存占用才8G出头24G余量非常大。如果换成12G的卡4路并行就会紧巴巴的。当然它的短板也很明显生态。CUDA生态积累了几十年PyTorch、TensorRT、ONNX Runtime随便一个都是开箱即用。昇腾这边虽然CANN这几年进步很快但很多操作还是得手动做模型转换、算子适配坑比CUDA那边多不少。所以这块卡适合的是那些愿意花时间消化技术细节、追求极致能效比和国产化栈的团队不适合只想“开箱即用”的人。2. 部署YOLO前的环境准备与软件栈搞清楚硬件是什么之后接下来就是实际操作了。很多人买了Atlas 300V 24G之后第一件想干的事就是把熟悉的YOLO模型跑起来。方向没错但如果你把平时跑GPU那套流程原封不动搬过来大概率会卡在环境搭建这一步。2.1 这台卡真正的主场CANN不是CUDAAtlas系列卡不认CUDA它有自己的软件栈最底层叫CANNCompute Architecture for Neural Networks。你没法在它上面直接跑import torch然后model.cuda()也没法直接加载TensorRT的engine文件。所有模型必须先转换成昇腾的OM格式再通过ACLAscendCL接口加载执行。这个“模型转换ACL推理”的流程其实就是昇腾平台和GPU平台最核心的区别。理解了这个区别后面所有操作都顺理成章了。CANN从底层往上大致分为几层驱动固件层负责让操作系统认出硬件CANN工具包提供模型转换工具ATC和运行时库再往上就是AscendCL推理接口。如果你用的是MindSpore框架还有更上层的封装。但对大多数人来说实际用到的就是ATC工具和ACL API这两样。我第一次接触这套栈的时候也犯过迷糊总觉得少了点什么。后来想明白了它就是把你熟悉的“PyTorch训练 - ONNX导出 - TensorRT构建engine”这条链路换成了“PyTorch训练 - ONNX导出 - ATC转OM - ACL加载执行”。思路是一路的只是每一环的工具和坑都不一样。2.2 固件、驱动、CANN版本怎么配才不踩坑环境配置是我踩坑最深的环节没有之一。Atlas的驱动、固件和CANN三者之间有严格的版本配套关系不是说你装个最新驱动就能配最新CANN。官方文档里有一个版本配套表每次安装前必须核对否则就会出现“卡能被系统识别但加载模型报错”这类诡异的兼容性问题。以我目前使用的版本组合为例驱动用的是合适的版本固件配套升级CANN版本与之匹配。当你安装的时候建议去官网下载对应产品型号的“Ascend HDK”和“CANN Toolkit”按照文档里的顺序先装驱动再装固件最后装CANN每装完一步最好重启一下。安装过程有几个容易忽略的细节驱动安装完成后用npu-smi info命令查看卡是否被正常识别。如果显示No devices found先别急着折腾软件检查一下卡是否插到位、供电是否接好。固件升级必须在驱动装好之后做而且升级过程中绝对不能断电否则卡可能变砖。CANN安装时推荐用root用户或者有sudo权限的用户因为它会往/usr/local/Ascend下写一堆库文件和环境变量脚本。装完后记得source /usr/local/Ascend/ascend-toolkit/set_env.sh否则后续命令找不到ATC工具会报command not found。另外提一句很多教程会让你直接用官网的Ascend-cann-toolkit包但那个包是分架构的x86_64和aarch64要区分开。我看过不少人下了x86_64的包往ARM服务器上装结果装了半小时发现架构对不上。3. 模型转换把YOLO从PyTorch搬到昇腾环境配好之后真正有意思的部分才开始。把YOLO模型从PyTorch迁到Atlas上核心动作就一步把PyTorch的权重文件转成昇腾的OM模型。但这个转换过程里藏着不少细节每一步都可能决定你最终推理性能的上限。3.1 ONNX导出时的几个关键设置昇腾的ATC工具不能直接吃PyTorch的.pt文件它只认ONNX或者MindSpore的模型格式。所以第一步永远是先导出ONNX。如果你用的是YOLOv5官方仓库里自带export.py但直接导出的话会踩坑。最典型的问题是PyTorch的某些算子ONNX不支持或者导出之后算子的排列方式不利于昇腾的AI Core计算。我总结了一套相对稳定的导出参数虽然不是万能的但至少能让你少来回折腾几轮。python export.py --weights yolov5s.pt --include onnx --opset 11 --simplify这里--opset 11是关键ONNX的算子集版本不是越高越好。opset 12以上的某些算子比如一些动态shape相关的算子ATC转换时支持并不完善反而opset 11最稳。--simplify会调用onnx-simplifier做一轮图优化去掉一些冗余节点这对ATC转换成功率有直接帮助。导出之后建议用onnx.checker验证一下模型结构完整性再用onnxsim检查一遍是否有动态shape。昇腾的ATC对动态shape支持比较弱如果你导出ONNX时输入shape带了batch维度为-1或者宽高不是固定值转换时大概率报错。最稳妥的做法是直接固定输入尺寸比如640x640。3.2 ATC转换命令与参数选择拿到干净的ONNX模型之后接下来就是ATC转换。这个工具是昇腾的模型转换器可以把ONNX、MindSpore或者TensorFlow的模型转换成一个.om文件这个.om文件才是真正能在Atlas卡上跑的东西。我的基础转换命令长这样atc --modelyolov5s.onnx \ --framework5 \ --outputyolov5s_bs1 \ --input_shapeimages:1,3,640,640 \ --soc_versionAscend310P3 \ --output_typeFP16 \ --insert_op_confaipp.cfg几个参数解释一下framework5表示输入的是ONNX模型如果是MindSpore就填1TensorFlow就填3。soc_version要根据你的芯片型号填。Atlas 300V 24G用的是昇腾310P系列芯片具体是310P3还是310P这取决于你的卡的具体型号和CANN版本用npu-smi info可以查到芯片型号或者直接看CANN文档里产品型号和soc_version的对应关系。填错的话转换能过但加载到卡上会报设备不支持的错。output_typeFP16表示权重精度转成FP16。ONNX模型里权重本来是FP32的转成FP16可以减少一半显存占用推理速度也有提升精度损失在可接受范围内。insert_op_confaipp.cfg是图像预处理配置这个是关键。你可以在AIPP里配置图像的缩放、减均值、除方差等操作让这块卡在硬件层面完成预处理CPU都不用干活。我的aipp.cfg长这样aipp_op { aipp_mode: static input_format: RGB888_U8 src_image_size_h: 640 src_image_size_w: 640 csc_switch: true rbuv_swap_switch: false min_chn_0: 0 min_chn_1: 0 min_chn_2: 0 var_reci_chn_0: 0.003921569 var_reci_chn_1: 0.003921569 var_reci_chn_2: 0.003921569 }这段配置的意思是输入图像是RGB888格式宽高都是640通道值先减0也就是不减排均值再乘1/255也就是var_reci_chn设为0.00392做归一化。配合YOLOv5官方的预处理逻辑这样在板卡上做图像缩放和归一化能省下CPU不少力气。转换成功后你会得到一个.om文件下一步就是写推理代码了。4. 推理代码怎么写ACL API实操模型转换只是万里长征走完了一半。接下来要做的是写一套推理程序让OM模型在Atlas 300V 24G上真正跑起来。官方推荐的开发方式是使用AscendCL接口这套接口可以用C或Python调用。C性能最好但代码量大Python写起来快适合快速出原型。我建议第一版先用Python把流程跑通再去考虑C优化。4.1 初始化与资源申请不写太多废话先给一个Python版本的最小可用框架pip install pyopencv pillow numpy pip install /path/to/ascend-toolkit/latest/python/acl/acl-*.whl然后看代码整套ACL推理的常规流程是初始化 - 申请设备 - 加载模型 - 准备输入输出内存 - 执行推理 - 解析输出。这里我把核心的初始化部分贴出来import acl import numpy as np import cv2 # 初始化ACL ret acl.init() assert ret 0, facl.init failed: {ret} # 申请设备0表示第一张Atlas卡 ret acl.rt.set_device(0) assert ret 0, facl.rt.set_device failed: {ret} # 创建上下文推理必须在上下文里执行 context, ret acl.rt.create_context(0) assert ret 0, facl.rt.create_context failed: {ret} # 加载模型 model_path yolov5s_bs1.om model_id, ret acl.mdl.load_from_file(model_path) assert ret 0, facl.mdl.load_from_file failed: {ret} # 获取模型的输入输出维度信息 model_desc acl.mdl.create_model_desc() ret acl.mdl.get_desc(model_desc, model_id) input_size acl.mdl.get_num_inputs(model_desc) output_size acl.mdl.get_num_outputs(model_desc)这里要注意ACL里所有的ret返回值都必须检查任何一个非0都代表失败。我见过不少人写完代码完全不检查返回值结果模型加载失败之后后面所有推理都在空指针上操作报了一堆莫名其妙的段错误排查半天才找到根因。acl.rt.create_context这一步非常关键它相当于创建了一个执行环境。后面申请内存、执行推理都必须在这个上下文里进行。如果你在没创建上下文的情况下直接调推理接口大概率会报错或者卡死。4.2 数据预处理注意事项模型加载好之后下一步是把输入图像处理成模型要求的格式拷贝到设备内存里去。Atlas 300V 24G的输入内存是必须通过acl.rt.malloc申请的不能直接用numpy数组的地址。这也是很多人第一次写ACL程序时最不适应的点。你平时用PyTorch时tensor.cuda()帮你把数据拷到显存里了但在ACL里这个拷贝动作要自己手动完成。# 用numpy读图和缩放 img cv2.imread(test.jpg) # BGR img cv2.cvtColor(img, cv2.COLOR_BGR2RGB) img cv2.resize(img, (640, 640)) img img.astype(np.uint8) # 申请设备内存 input_data np.ascontiguousarray(img) input_size input_data.nbytes dst_ptr, ret acl.rt.malloc(input_size, 2 * 1024 * 1024) # 2MB对齐 assert ret 0 # 把数据拷贝到设备内存 acl.rt.memcpy(dst_ptr, input_size, input_data.ctypes.data, input_size, acl.rt.MEMCPY_HOST_TO_DEVICE)这里你可能注意到我没有做归一化操作。因为我在AIPP里已经配置过了输入模型的数据应该就是原始0-255的RGB值AIPP会自动帮你减均值、缩放。如果你在主机端又归一化了一次等于做了两次归一化结果肯定不对。实际开发中有几个容易踩的坑acl.rt.malloc的第二个参数要传内存对齐大小一般是2MB的倍数。传0或者传太小某些CANN版本会返回非法参数。输入图像的宽高必须和模型输入完全一致如果模型是640x640你喂了一张608x608的图不会报错但推理结果会非常离谱。多batch推理时要保证所有图像的尺寸一致不能一个batch里有不同分辨率。推理本身其实只有一行ret acl.mdl.execute(model_id, input_data_ptr, input_size, output_ptr, output_size)执行完之后输出数据在output_ptr里需要把它拷回CPU内存再解析。这里模型输出的格式和YOLOv5原生输出不太一样ONNX导出的模型输出往往是三个尺度的特征图每个尺度维度是[1, 3, 80, 80, 85]这种形式80x80是特征图网格数85是4个框坐标1个目标置信度80个类别需要自己写解码逻辑把框坐标还原到原图尺寸再做NMS非极大值抑制。5. 性能调优与典型问题排障模型跑通了只是及格线。真正让Atlas 300V 24G发挥出它的价值是把性能调优也做起来。同时在实际部署中遇到的问题往往比网上教程写的多得多我在下面把最常见的问题和排查思路整理出来。5.1 第一次跑起来很慢先查这三个地方不少人在Atlas上第一次跑通YOLO测出来的延迟比CPU还慢心态直接崩了。别急大概率不是硬件不行而是有这三个问题没有处理。第一个问题没用上AIPP主机端预处理拖了后腿。如果你没有在ATC转换时配置aipp.cfg那么图像缩放、归一化这些操作都要在主机端用CPU完成然后再把处理好的数据拷贝到设备。这不但让CPU忙成狗还会占用PCIe带宽。表现就是CPU占用率飙升卡上的算力利用率却很低。解决办法就是回头看我上面给的aipp.cfg把能沉到硬件上的计算都沉下去。第二个问题数据拷贝没有走异步。ACL提供同步执行接口和异步执行接口。同步执行就是字面意思模型跑完数据拷回来程序才能进行下一步。异步执行则可以让PCIe传数据的同时卡上还在跑上一个推理相当于把数据搬运和计算时间重叠起来。显式使用acl.rt.memcpy_async和acl.mdl.execute_async之后多路视频流场景下整体吞吐能提升20%-30%。第三个问题模型没有量化。前面反复提到这块卡的INT8算力是FP16的两倍。如果你的模型能容忍精度损失量化是提升性能最直接的手段。量化通常需要一些校准数据工具链里也有对应的用法。我的经验是YOLOv5s做INT8量化后mAP损失通常在0.5-1个点左右但推理延迟基本能砍半。对于视频流分析这种场景完全值得。5.2 内存不足与算子不支持在实际推理中我遇到最多的报错就两类一类是acl.mdl.execute时报内存不足E_NPU_ALLOC_FAILED另一类是模型转换时报算子不支持E10010之类。内存不足的原因通常不是显存真的不够而是没有复用内存。如果你每次推理都重新acl.rt.malloc申请输入输出内存推理完又忘记acl.rt.free时间长了内存碎片会越来越多最终导致申请失败。正确做法是在程序启动时申请好输入输出内存推理过程中一直复用只在程序退出时释放。一副内存用到天荒地老。另外如果你在多线程或多进程里同时跑多个推理要注意acl.mdl.execute默认是阻塞的。多线程场景下必须自己做好互斥否则可能发生多线程同时访问同一块设备内存的情况导致数据错乱或者崩溃。算子不支持的报错相对麻烦一些。它的含义是ONNX模型里有某个算子在昇腾芯片上没有对应实现。遇到这种情况除了等新版本CANN补充算子外更通用的做法是回ONNX导出阶段换实现方式。比如某些模型用了GridSample、CumSum这类算子ATC转换时就容易报不支持。你可以去onnxruntime或者PyTorch里找替代实现或者干脆在导出ONNX之前把模型结构改一下用等价的基础算子替换掉不支持的算子。我这里有一个排查顺序供你参考先看CANN版本是不是太旧升级到当前产品支持的最新版本很多算子都靠新版本补齐。再查ONNX模型里哪些节点不属于支持的算子列表用onnx_graphsurgeon一类的工具按节点名称逐一排查。如果就是某个特殊算子不支持用一个CPU算子或者等价的基本算子组合去替代。还有一个不算少见的坑模型转换时报内存不足。这通常不是电脑内存不够而是ATC工具在解析大模型时默认的线程数或内存池太小。可以在ATC命令里加--job_type2调整资源模式或者减小输入batch size再转一次试试。5.3 一个真实的调优案例拿我这边一个实际项目来说需求是16路1080p视频流实时检测用的模型是YOLOv5s。最初版本是在GPU上跑的部署到Atlas 300V 24G之后第一版延迟大约18毫秒每帧16路视频流要达到25fps的实时性要求明显吃紧。于是我做了三轮优化第一轮配置AIPP把图像缩放和归一化下沉到硬件CPU占用率降下来延迟降到15毫秒。第二轮换成异步推理模式输入图像按队列管理连续两帧的预处理和推理时间重叠延迟降到11毫秒。第三轮用少量校准数据把模型量化成INT8延迟直接降到6毫秒以下单卡跑16路视频流甚至有接近一半的余量。整个过程大概花了两天时间主要时间都花在理解工具链和调试细节上。一旦把这套流程理顺了调度多路视频流、管理多块卡其实就是改改配置和手动加一轮资源池管理的事。6. 这块卡还能怎么用场景扩展与后续建议Atlas 300V 24G能干的远不止YOLO目标检测这一件事。我现在主要拿它做视频结构化分析一套流程里同时跑检测、跟踪和属性识别三个模型。24G大显存的好处在这里体现得很明显一个检测模型加一个ReID行人重识别模型再加一个车辆属性识别模型三个模型同时常驻显存单卡就搞定了一条流水线。另外如果你做的是OCR类项目PaddleOCR的检测、方向分类、文字识别三个模型也可以同时常驻省去频繁加载模型的I/O开销。工业质检这种场景也适合图片尺寸大、需要精度高的检测模型大多数本身不太吃资源但图多、并发高很适合这种低功耗、高能效比的推理卡。部署形态上如果想做集群可以在一台x86服务器上插多张Atlas卡。Atlas 300V 24G是单槽位低功耗设计供电和散热压力小一张服务器插四张卡完全可行。多卡调度可以通过AscendCL的设备编号或者容器化方案来做每张卡分配一个device_id就行。我个人实际使用中的体会是Atlas平台最需要学习成本的地方其实不是硬件而是那套和CUDA生态完全不同的软件栈。一旦接受了“模型转换ACL推理”这个范式你会发现它并不比TensorRT难太多只是资料少、教程少遇到问题要多花些时间翻官方文档。但反过来想正因为用的人少你踩通了这些坑之后积累的经验价值反而更高。最后分享一个小技巧在CANN安装目录的tools下有一个msopst工具还有一堆性能分析和dump辅助脚本性能调优时务必利用起来。用它能直接看到模型里每个算子在AI Core上的执行耗时比盲猜哪一步慢要高效得多。我做INT8量化性能对比时就是用这个工具一眼看出某个Transpose算子占了大头改掉之后整体延迟又降了一截。这种细节文档里翻半天可能都找不到但实际排查问题时是真的救命。
企业数字化 ERP 产品动态
相关推荐
ab173懒人网站:零配置JSON格式化急救工具 1. ab173懒人网站到底是什么:不是工具,而是“JSON急救包”很多人第一次在搜索引擎里敲下“ab173 懒人网站”,点进去看到那个极简的白色界面——顶部一行输入框、中间一个大按钮“格式化”,底下直接输出带缩进和颜色的JSON——第一… · 2026/9/25 6:50:48
区块链状态订阅框架substrate:跨链消息可靠投递与重组处理实战 1. 从一条命令行说起:substrate 到底在解决什么问题第一次接触 substrate 这个词,是在一个做跨链数据同步的项目里。当时团队需要把一条业务链上的状态变更,实时同步到另外几条异构链上,同时还要保证每条链上的数据最终一致。最初… · 2026/9/25 6:50:42
十款HTML+CSS+JS登录注册界面模板:从玻璃拟态到粒子动画的交互设计实战 写登录注册界面这件事,说难不难,说简单也真不简单。很多朋友做完功能就能跑,但视觉和交互总差那么点意思。我自己前后做了不下二十套登录注册页面,从纯静态到带细交互的,踩过的坑比写过的表单还多。这套“HTMLCSSJS十款… · 2026/9/25 6:50:42
华为Atlas 300V部署YOLOv5全流程实战:从硬件选型到性能调优 如果你最近在折腾AI落地,那你大概率躲不开一个名字:Atlas。这名字听着像个尖端实验室,但它其实是华为昇腾体系下的AI计算平台,覆盖从训练侧到推理侧的一整套硬件和软件栈。而我之所以深入研究这套东西,就是因为一个很现… · 2026/9/25 7:22:49
Bellhop水下声场建模入门:从.env文件到传播损失计算 /* 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 7:22:49
IIS日志中的布尔盲注分析实战:从闽盾杯到真实攻防 1. 这不是一道CTF题,而是一次真实攻防现场的复盘“网络安全日志分析-题集1-[闽盾杯 2021]日志分析”——光看标题,很多人会下意识划走:又一道CTF模拟题,无非是给点Apache日志、写个Python脚本、跑出flag完事。但我在福建某市网信办… · 2026/9/25 7:22:24
Origin主成分分析(PCA)完全指南:从数据标准化到得分图绘制 /* 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 7:22:18
低功耗遥测终端机RTU选型指南:从功耗核算到Modbus RTU对接实战 /* 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 7:22:18
创维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