news 2026/9/7 6:22:32

谁在跟你抢PCIe?一文看懂链路协商与带宽排查

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
谁在跟你抢PCIe?一文看懂链路协商与带宽排查

标题里的“谁在跟你抢 PCIe?”不是一句文案,而是一条 MiniMax-H3 竖屏短片想讲清楚的问题:一块主板上同时挂着 GPU、NVMe、网卡、FPGA 加速卡,它们都在通过 PCIe 申请链路、带宽和中断资源。短片用竖屏动画把“抢”这个动作做得很直观,但看完之后真正需要搞明白的是:抢的到底是什么、怎么查谁在抢、设备认不出来或链路降速时应该从哪一步开始排查。

这篇不讨论 AI 视频生成的提示词,只讲 PCIe 本身。内容会覆盖链路协商、设备枚举、ACS 冲突、带宽争抢验证、批量巡检脚本,以及 Linux 和 Zynq/FPGA 场景下最常用的排查命令。适合刚接触 PCIe 驱动开发、遇到过 PCIe 设备不识别、或者发现多卡机器带宽跑不满的读者。如果你打算做一条同主题竖屏短视频,这篇的技术清单也能直接当脚本素材。

1. 核心能力速览

能力项说明
主题范围PCIe 资源竞争、链路协商、设备枚举、ACS 冲突、带宽排查
涉及协议PCIe 链路训练、配置空间、ACS、AER、MSI/MSI-X、IOMMU
支持平台Linux、Windows、Zynq/FPGA 嵌入式平台
核心工具lspci、setpci、dmesg、sysfs、Vivado、PCIe test suite
批量任务支持通过脚本对整机所有 PCIe 设备批量采集链路状态
接口能力PCIe 本身不是 HTTP API,但 Linux sysfs 提供可编程采集接口
硬件门槛需要有 PCIe 接口的台式机、服务器或 Zynq 开发板
适用人群驱动开发、FPGA 调试、运维排障、多卡工作站使用者
风险评估涉及硬件配置操作,部分调试命令和 BIOS 参数调整需谨慎执行

这套内容不需要特殊型号的显卡,也不需要固定显存规模,核心是一个“能跑 lspci 的操作系统”加一份“能插 PCIe 设备的硬件”。

2. 适用场景与使用边界

什么情况下你会遇到“有人在抢 PCIe”?

第一种是多卡工作站。一张 GPU 在做训练,另一张 GPU 在渲染,中间 NVMe 还在写数据集,所有数据都要经过 CPU 的 Root Port 或者 PCIe Switch,共享链路一拥堵,训练速度就掉。第二种是服务器扩容,插了多张网卡和 RAID 卡,结果 BIOS 枚举后某张卡带宽变成 x4 而不是 x16。第三种是 FPGA 开发板调试,自己在 Zynq 上例化了一个 PCIe Root Complex,接上端点设备后发现 lspci 里根本看不到。

这些场景都能用同一套方法排查:先看拓扑,再看链路协商结果,最后定位瓶颈和错误。

使用边界也要说清楚。PCIe 排查能解决的是链路协商、枚举顺序、带宽不足、设备识别异常、ACS 隔离问题。它不能替代逻辑分析仪和协议分析仪,也不能处理 PCB 设计阶段的高速信号完整性问题。另外,对生产环境执行 BIOS 参数修改、驱动参数注入、设备复位或热插拔前,需要确认设备归属和授权范围,避免影响正在运行的服务。

3. PCIe 资源竞争的本质:链路、端口、带宽都要看

3.1 PCIe 链路与 Lane 协商

PCIe 是点对点串行总线,每个设备通过一条或多条 Lane 与对端连接。Lane 是收发差分对,一条链路可以包含 1、2、4、8、16 条 Lane,体现在设备命名上就是 x1、x4、x8、x16。

链路两端在上电后要完成一个叫 LTSSM 的链路训练流程,状态机依次经过 Detect、Polling、Configuration、L0 等状态,最终协商出双方都能接受的速率和宽度。协商结果不代表设备能力,只代表当前物理连接能达到的结果。

代际单 Lane 速率编码方式x16 单向理论带宽
PCIe 1.02.5 GT/s8b/10b约 3.93 GB/s
PCIe 2.05 GT/s8b/10b约 7.86 GB/s
PCIe 3.08 GT/s128b/130b约 15.75 GB/s
PCIe 4.016 GT/s128b/130b约 31.5 GB/s
PCIe 5.032 GT/s128b/130b约 63 GB/s

这里的 GT/s 是每秒传输的 Giga Transfers,包含编码开销,实际有效带宽要按编码效率折算。所以同样写着 PCIe 4.0 x16,跑数据处理时看到的内存拷贝吞吐不会等于 32 GB/s,而是接近 31.5 GB/s 甚至更低。

“抢带宽”最常见的表现就是协商宽度低于预期,例如显卡槽位物理是 x16,但插上后 lspci 显示 negotiated width 只有 x8。这可能是插槽被机械阻挡、后端缺少 Lane、BIOS 分流配置或金手指接触问题。

3.2 被忽略的共享瓶颈:PCIe Switch 与上行链路

很多人以为设备数量越多总带宽越大,这是误解。PCIe Switch 的作用是扩展端口数量,但它内部有一个上行端口连接 Root Complex,所有下行端口的数据都要通过上行端口转发。

一个典型拓扑是这样的:

  • CPU Root Port 0 直连 GPU
  • CPU Root Port 1 直连 NVMe
  • CPU Root Port 2 连接 PCIe Switch
  • PCIe Switch 下行挂着网卡 A、网卡 B、RAID 卡

前两条链路是 CPU 直连,独占带宽;第三条链路通过 Switch 扩展出来的所有设备共享 Switch 的上行带宽。如果上行只有 PCIe 4.0 x8,上面挂了三张网卡,三张网卡同时跑满流量时,必然在上行端口拥堵。

排查这类问题要看完整拓扑,不能只看单个设备的协商状态。设备自身的 Link Status 正常,不代表它到 CPU 之间的通路没有共享瓶颈。

3.3 不止带宽:中断与地址空间也在抢

资源竞争不只是带宽。MSI/MSI-X 中断向量、BAR 地址空间、IOMMU 页表同样会冲突。

网卡启用多队列时依赖 MSI-X,每个队列需要一个中断向量,中断分配如果集中到同一个 CPU 核心,高流量下会出现 CPU 软中断占用过高,直观表现是“网卡没跑满但业务延迟很高”。GPU 和 FPGA 这类设备会申请较大的 BAR 空间,某些老主板的地址窗口分配不合理,会导致第二张卡 BAR 申请失败,系统直接不识别。

所以在回答“谁在跟你抢 PCIe”时,第一反应不该是去改设备,而是先获取整机的拓扑和资源分配现状。

4. 环境准备与前置条件

4.1 Linux 环境

Linux 下排查 PCIe 主要依赖 pciutils 和内核提供的 sysfs 接口。

安装工具:

# Debian/Ubuntu sudo apt install pciutils # RHEL/CentOS sudo yum install pciutils

大部分服务器和桌面发行版默认自带 lspci,安装后用 root 权限执行能看到完整链路信息。权限不足时,部分 config space 读取会被内核拦截,所以能 sudo 尽量 sudo。

4.2 Windows 环境

Windows 没有 lspci 原生命令,但设备管理器已经能看到设备是否存在、是否有感叹号、是否报错。更详细的链路速率和宽度可以在 BIOS 里看,也可以用 HWiNFO、GPU-Z 等工具查看。

Windows 下 PCIe 错误会以 WHEA 事件形式记录。如果系统中反复出现 WHEA-PCIe 警告,说明有 PCIe 设备触发了 AER 错误或链路降速,事件查看器里的来源和设备 Instance ID 能帮你定位是哪张卡、哪个 BDF。

4.3 FPGA 与嵌入式环境

如果你在 Zynq 或纯 FPGA 上调试 PCIe,需要准备:

  • Vivado 工程,用于例化 PCIe IP 核
  • 串口终端,用于查看启动日志
  • 逻辑分析仪或 VIO,用于观测 user_lnk_up、perst、时钟信号
  • 一块符合规范的 PCIe 端点设备,例如 NVMe 转接卡、网卡或自研 EP 逻辑

Zynq 的调试路径和普通服务器不太一样。普通服务器是 CPU 作为 Root Complex,系统固件自动做枚举;Zynq 上你既可以用 PS 端 PCIe 控制器,也可以在 PL 里例化 AXI PCIe Root Complex,枚举逻辑可能由裸机程序或 Linux 内核完成,每一步都要自己确认。

5. 实操一:看拓扑和链路协商

5.1 查看 PCIe 拓扑

先获取整机 PCIe 树状拓扑:

sudo lspci -tv

输出会显示总线号、设备号、功能号和设备类型。重点关注设备挂在哪个 Root Port 下面,是否有多设备共享同一个上游端口。

比如输出里看到:

-[0000:00]-+-00.0 Intel Host Bridge +-01.0-[01]----00.0 NVIDIA GPU +-1b.0-[03]----00.0 Realtek Ethernet

就说明 GPU 占了一条 Root Port,网卡挂在另一条 Root Port 下,两者不共享上行。如果看到某个 Root Port 下面带了一个 Switch,Switch 下面又带了三四个设备,那这个上行端口就是潜在的争抢点。

5.2 查看单设备链路

要查看某个设备的链路协商情况,用 -vvv 参数:

sudo lspci -vvv -s 01:00.0

重点看这几项:

LnkCap: Port #0, Speed 32GT/s, Width x16 LnkSta: Speed 32GT/s (ok), Width x16 (ok)

LnkCap 表示该设备所在的端口物理能力上限,LnkSta 表示当前实际协商结果。Speed 和 Width 任一比预期低,都需要追查原因。

内核 sysfs 也提供同样的信息:

cat /sys/bus/pci/devices/0000:01:00.0/max_link_speed cat /sys/bus/pci/devices/0000:01:00.0/max_link_width cat /sys/bus/pci/devices/0000:01:00.0/current_link_speed cat /sys/bus/pci/devices/0000:01:00.0/current_link_width

这套接口很适合写脚本,配合 for 循环就能批量输出整机每个设备的协商状态。

5.3 带宽协商的判断标准

判断标准不是“设备支持多少”,而是“当前协商了多少,是否满足业务需要”。

一张支持 PCIe 4.0 x16 的 GPU,如果插在物理 x8 的槽位上,协商宽度会是 x8。可以从 BIOS 的 PCIe Slot Configuration 中重新确认槽位 Lane 设置,也可以把卡换到 CPU 直连 x16 的槽位验证。

如果是通过 M.2 转接卡插 NVMe,转接卡只引出 x4 Lane,那么设备再快也只能用 x4 的带宽。要注意转接卡本身的质量,劣质转接卡可能导致高负载下链路直接降速到 x1。

6. 实操二:设备枚举与不识别问题排查

6.1 PCIe 枚举原理

PCIe 枚举由 Root Complex 发起。系统固件或内核首先扫描总线 0,通过配置读写事务发现 Root Port,然后为每个 Root Port 分配下一级总线号。如果下游存在桥或 Switch,则继续递归分配总线号,直到所有层级的设备都被遍历。

每次枚举都会读取设备的 Vendor ID 和 Device ID。如果读取结果是 0xFFFFFFFF,说明配置请求没有收到有效响应,系统会认为总线上不存在设备。

所以在 Zynq 上调试“PCIe 设备不识别”时,起点不是看驱动,而是看枚举阶段是否拿到了正确的 Vendor ID。

6.2 Zynq 调试 PCIe 设备的典型排查路径

在 Zynq 上,如果 PCIe 端点设备没有被枚举出来,按下面顺序排查:

第一步确认链路训练。查看 PL 中 PCIe IP 核的 user_lnk_up 信号,或者打印 PS-PCIe 的链路状态寄存器。链路没 up,后续所有枚举都没有意义。

第二步确认参考时钟。PCIe 需要 100 MHz 参考时钟,时钟幅度和 AC 耦合电容异常会导致训练一直重试。示波器或时钟芯片寄存器能确认输出。

第三步确认复位信号。PERST# 必须有效释放,设备在复位释放后才能进入 Detect 状态。常见问题是用 GPIO 拉复位后没有给足够延时。

第四步确认配置读取。在 CPU 侧通过 setpci 直接读端点的配置空间:

sudo setpci -s 01:00.0 VENDOR_ID.w sudo setpci -s 01:00.0 DEVICE_ID.w

如果读回来不是 0xFFFFFFFF,但系统 lspci 不显示,可能是枚举时序问题,需要调整设备 ready 时间。如果读回来全是 F,重点回到链路训练。

第五步检查 Vivado 中 AXI PCIe 的地址映射。例化 AXI PCIe Root Complex 后,AXI 地址窗口与 PCIe 地址之间要做 inbound/outbound 转换。outbound 是 CPU/PS 发起、发往 PCIe 设备的访问,inbound 是 PCIe 设备发起、发往内存的 DMA 访问。两边映射关系写错,设备就算枚举出来,DMA 也无法工作。

6.3 ACS 打不开与总线错误

ACS 全称 Access Control Services,作用是限制同一 PCIe 拓扑内的设备绕过 Root Complex 直接通信。虚拟化直通场景下,需要 ACS 把设备隔离,否则一个恶意或异常设备可能直接访问另一个设备的内存。

部分设备对 ACS 支持不完整,lspci 里看不到完整能力位,或者系统日志报告 ACS 冲突。Linux 启动参数里有一个常用选项:

pcie_acs_override=downstream,multifunction

这个参数会强制让内核为下游端口和多功能设备打开 ACS 行为。但要注意,它属于 workaround,不是设备原生支持,生产环境需要结合虚拟化和 IOMMU 需求评估后再使用。

与总线错误相关的是 AER 和 WHEA。Linux 下看:

sudo dmesg | grep -i "aer\|pcieport\|bus error"

如果反复出现 AER 报错,说明链路在运行中出现错误或降速。常见原因包括金手指接触不良、PCIe 卡功耗过高导致供电不稳、转接卡信号质量差、链路跑在 Gen4 但主板信号完整性不足。可以先在 BIOS 中把链路速率手动降到 Gen3,对比错误是否消失,以此判断是否是物理信号问题。

USB4 场景中也要注意,USB4 是通过 PCIe 隧道把 PCIe 事务封装在 Type-C 链路里传输,主机枚举出的外部设备本质还是 PCIe 设备。如果 USB4 外设识别异常,除了看设备管理器,还要确认 USB4 控制器固件和线缆是否为完整 40Gbps 规格,隧道带宽分配不足也会造成设备随机掉线。

7. 性能观察与带宽争抢验证

7.1 怎么判断带宽被抢

打开系统监控后,CPU、内存、磁盘、GPU 使用率都正常,但业务吞吐不达标,这时候就要怀疑 PCIe 链路是否成为瓶颈。最直接的观察点有三个:协商宽度是否满足设备能力、是否存在大量 PCIe 错误、设备吞吐是否远低于理论值。

GPU 场景可以用 nvidia-smi 查看 GPU 的 PCIe 信息:

nvidia-smi --query-gpu=index,name,pcie.link.gen.current,pcie.link.width.current --format=csv

输出类似:

0, NVIDIA GeForce RTX 4090, 4, 16

这里显示的是当前协商的 PCIe 代际和链路宽度,不代表实时带宽占用,但能判断链路是否到达能力上限。如果 GPU 是 Gen4 x16,输出却只有 3 和 8,链路已经降速。

NVMe 场景可以用 dd 或 fio 做顺序读,同时观察 CPU 侧 PCIe 错误计数,判断高负载下链路是否稳定:

dd if=/dev/nvme0n1 of=/dev/null bs=1M count=8192

如果高负载时 dmesg 出现 AER 错误,基本可以确定 PCIe 链路在高速率下不稳定。

7.2 实测方案设计

要验证“谁在抢带宽”,不建议直接用复杂业务压测,先做基线测试。

第一步,单独测每类设备的极限吞吐。例如单独跑 NVMe 顺序读,记录吞吐;单独跑 GPU 显存拷贝或渲染任务,记录帧率。第二步,让多个设备同时满负荷运行,再次记录吞吐。第三步,比较前后数据。如果单跑时 NVMe 能到 6500 MB/s,GPU 同时满载后降到 3000 MB/s,说明两者在上行链路或 CPU 侧资源上产生了竞争。

多网卡场景可以本机开 iperf 服务,让多张网卡同时收发:

iperf3 -s iperf3 -c 127.0.0.1 -P 4

回环路径不一定走 PCIe,更可靠的是接两台机器,分别从不同网卡打流量,观察 Switch 上行端口是否成为瓶颈。

7.3 降低争抢的方向

  • 优先把高带宽设备挂到 CPU 直连 Root Port 上。
  • 减少 PCIe Switch 级联层级,避免多设备共享窄上行。
  • 对不要求高可靠性的场景,可以关闭未使用板载设备释放 Lane。
  • BIOS 中确认 PCIe Slot Configuration,避免 x16 槽被拆分为 x8/x4。
  • 筛选链路速率,从 Gen4 降到 Gen3,如果性能损失可接受,能显著提高链路稳定性。
  • 确认所有设备固件和驱动已更新,很多“掉链”问题由固件 bug 引起。

8. 接口与批量巡检脚本

8.1 Linux sysfs:PCIe 的“可编程接口”

PCIe 没有传统意义上的 REST API,但 Linux 把每个 PCIe 设备都暴露在 /sys/bus/pci/devices/ 目录下,可以通过读取文件和写文件的方式获取状态或触发重置。这相当于内核提供的可编程接口。

常用文件路径:

/sys/bus/pci/devices/0000:01:00.0/vendor /sys/bus/pci/devices/0000:01:00.0/device /sys/bus/pci/devices/0000:01:00.0/current_link_speed /sys/bus/pci/devices/0000:01:00.0/current_link_width /sys/bus/pci/devices/0000:01:00.0/irq /sys/bus/pci/devices/0000:01:00.0/resource

写巡检脚本时优先读 sysfs,比解析 lspci 文本更稳定。

8.2 批量采集所有 PCIe 设备带宽状态

下面这个 Python 脚本可以批量扫描整机 PCIe 设备,输出当前链路速率和宽度,适合做巡检基线:

import os import glob base = "/sys/bus/pci/devices" for dev in sorted(glob.glob(f"{base}/*")): bdf = os.path.basename(dev) def read_file(name): try: with open(os.path.join(dev, name), "r") as f: return f.read().strip() except FileNotFoundError: return "N/A" vendor = read_file("vendor") device = read_file("device") max_speed = read_file("max_link_speed") cur_speed = read_file("current_link_speed") max_width = read_file("max_link_width") cur_width = read_file("current_link_width") irq = read_file("irq") print(f"{bdf} | vendor={vendor} device={device} | " f"link {cur_speed}/{max_speed} width {cur_width}/{max_width} | irq={irq}")

脚本输出示例:

0000:01:00.0 | vendor=0x10de device=0x2684 | link 16GT/s/16GT/s width 16/16 | irq=81 0000:02:00.0 | vendor=0x144d device=0xa80a | link 16GT/s/16GT/s width 4/4 | irq=82

实际 vendor ID 与设备对应关系以机器为准,脚本只负责采集。把输出保存成 CSV 后可以对比前后状态,快速发现降速设备。

8.3 批量检查 AER 错误

巡检不仅要看状态,还要看错误计数。Linux 下 AER 错误统计可以通过 aer_inject 等方式注入,日常巡检直接读 dmesg 更简单:

sudo dmesg -T | grep -i "aerr\|pcieport" | tail -50

更自动化一点,可以定时执行一条命令,把错误信息追加到日志文件:

echo "=== $(date) ===" >> /var/log/pcie_check.log sudo dmesg -T | grep -i "aer" | tail -20 >> /var/log/pcie_check.log

如果脚本发现日志里持续出现同一个 Root Port 的 AER 错误,例如:

pcieport 0000:00:1b.0: AER: Corrected error received: 0000:02:00.0

说明对应设备链路存在稳定性问题,需要考虑降速、更换转接卡或清洁金手指。

9. 常见问题与排查方法

问题现象可能原因排查方式解决方案
lspci 看不到设备链路没有训练成功,或配置空间读回全 F检查 PERST#、参考时钟、电源,读 user_lnk_up修复硬件复位时序,确认时钟输出,重新训练链路
链路协商宽度只有 x4,预期 x16槽位 Lane 不足、BIOS 拆分、金手指接触不良lspci -vvv 查看 LnkSta,在 BIOS 核对 Slot Configuration更换槽位,恢复 BIOS 默认 PCIe 配置,清洁金手指
协商速率降级到 Gen1/Gen2信号质量差、转接卡劣质、链路不稳定dmesg 看 AER 报错,手动锁定 Gen3 对比更换线缆/转接卡,BIOS 固定速率,降低链路工作频率
性能吞吐跑不满上行链路共享带宽不足多设备同时压测,观察 Switch 拓扑把高带宽设备移到 CPU 直连端口,减少共享级联
ACS 无法打开设备未完整实现 ACS 能力lspci -vvv 查看 ACSCap按场景评估 pcie_acs_override 参数,优先换支持 ACS 的设备
Windows 出现 WHEA-PCIe 错误PCIe 链路错误、驱动或固件异常事件查看器读 Instance ID,配合 dmesg 类日志定位更新 BIOS 和驱动,清理转接卡,必要时降速
Linux dmesg 报 pcie bus error链路错误率上升,访问请求异常查看 AER 报错设备,观察高负载是否复现检查供电、接触、线缆,降低速率并重压测试
Zynq 上端点设备不枚举PL 里 PCIe RC 未完成训练或 AXI 地址映射错误检查 user_lnk_up,用 VIO 观测信号,核对 inbound/outbound 映射修复映射关系,确认时钟复位,重新生成 bitstream
USB4 外设偶尔掉线USB4 隧道带宽不足或线缆规格不达标更换 40Gbps 完整线缆,在系统日志确认隧道 PCIe 协商保证线缆规格,减少同时占用 USB4 带宽的传输任务
设备插上后系统卡死或重启设备 BAR 冲突、供电不足、固件兼容性问题记录日志,确认新增设备 BDF 与 BAR 分配BIOS 更新,更换供电,按最小系统逐步添加设备

10. 最佳实践与合规边界

PCIe 调试最怕的是没有基线。建议第一次装机或接到新开发板时,先保存一份完整的 lspci -vvv 输出、dmesg PCIe 相关日志、BIOS PCIe 配置截图。这样后面出现不识别或带宽下降时,可以直接对比差异。

工程化部署建议:

  • 把巡检脚本接入定时任务,每天记录链路状态、错误计数。
  • 输出结果按日期归档,文件名带上主机名。
  • 批量修改 BIOS 参数或驱动参数前,先在单台测试机验证。
  • FPGA 工程做 PCIe 调试时,保留一个只包含最小 RC 的工程,排除用户逻辑干扰。
  • 做带宽压测时先确认负载不会影响正在运行的业务。

合规和隐私方面要特别提醒。PCIe 调试会读取配置空间、BAR 地址、DMA 地址,这些信息在特定环境下可能涉及设备固件细节和企业内部数据。调试他人设备、服务器或 FPGA 板卡前,必须确认授权范围。不要用 PCIe 漏洞或 ACS workaround 去绕过安全机制,也不要把采集到的设备信息、日志数据向外传播。

如果需要从设备中读取存储数据,例如用 NVMe 直通做测试,务必遵守数据安全要求,测试结束后销毁临时数据。

11. 总结与下一步

“谁在跟你抢 PCIe”这个问题,本质是链路、带宽、中断、地址空间四个维度的竞争。最先要验证的不是设备性能,而是协商结果:打开 lspci -vvv,确认 Speed 和 Width 是否达到预期;再看拓扑,确认设备之间是否共享上行链路;最后用多设备并发压测,判断真正的瓶颈。

最容易踩的坑有三个:把端口数量误以为带宽翻倍、不保存基线就直接改 BIOS、在 Zynq 上忽略链路训练直接查驱动。这三个坑对应同一件事:先确认物理链路,再谈软件配置。

下一步如果还想深入,可以继续看 PCIe 6.0 的 PAM4 编码和 CXL 对资源池化的影响,也可以把巡检脚本扩展成一个小型 Web 服务,用图表展示每台机器的 PCIe 链路健康度。这块既适合做 FPGA 方向的技术积累,也适合服务器运维场景落地。建议先把今天的 lspci 基线命令保存下来,下次遇到“设备又慢了”的时候,你会感谢当初留了这份记录。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/7 6:19:46

AI-Edge边缘计算实战:从模型压缩到TensorRT部署的完整指南

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

作者头像 李华
网站建设 2026/9/7 6:17:45

用Excel VBA打造进销存系统:从表结构到自动记账全解析

简介:一套面向中小企业与Excel进阶用户的进销存管理系统VBA实现资源,围绕采购、销售、库存和报表四大核心流程,提供低成本且可灵活定制的业务管理方案。压缩包内共3个文件,包括可直接运行的主工作簿xlsm文件、用于关联关系的rels文…

作者头像 李华
网站建设 2026/9/7 6:14:53

Unity游戏开发:宝可梦机甲变身盲盒系统完整实现指南

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

作者头像 李华