性能基准测试
性能基准测试
Section titled “性能基准测试”基于不同规模数据集对 8 种存储结构进行创建/查询/遍历/修改性能测试
测试环境: AMD Ryzen 7 · 32GB RAM · MoonBit native 后端
一、测试方法论
Section titled “一、测试方法论”| 操作 | 描述 | 测试方式 |
|---|---|---|
| 建图 (add_edge) | 批量添加 N 个节点 + M 条边 | 总耗时 / 边数 |
| 邻居查询 (neighbors) | 查询单个节点的所有邻居 | 平均耗时 / 次 |
| 边查询 (contains_edge) | 检查某条边是否存在 | 平均耗时 / 次 |
| 全边遍历 (edges) | 迭代所有边 | 总耗时 |
| 内存占用 | 建图后的内存使用 | memory 统计 |
| 规模 | 节点数 | 边数 | 代表场景 |
|---|---|---|---|
| S | 100 | 500 | 教学演示、小图分析 |
| M | 10,000 | 50,000 | 社交网络子集、中等图 |
| L | 100,000 | 1,000,000 | 完整社交网络、引用网络 |
| XL | 1,000,000 | 10,000,000 | Web 图、大规模知识图谱 |
二、建图性能
Section titled “二、建图性能”测试从空图开始,逐条添加 N 个节点 + M 条边的总耗时(毫秒)。
小型图 (100 节点, 500 边)
Section titled “小型图 (100 节点, 500 边)”| 存储 | 耗时 | 相对速度 |
|---|---|---|
| DirectedAdjList | 0.12 ms | ⭐ 1.0× |
| UndirectedAdjList | 0.10 ms | 1.2× |
| DirectedMatrix | 0.08 ms | 1.5× |
| EdgeList | 0.09 ms | 1.3× |
| CSR (Builder) | 0.15 ms | 0.8× |
小图场景差异不大,所有存储均在亚毫秒级完成。
中型图 (10K 节点, 50K 边)
Section titled “中型图 (10K 节点, 50K 边)”| 存储 | 耗时 | 相对速度 | 特点 |
|---|---|---|---|
| DirectedAdjList | 8.2 ms | ⭐ 1.0× | 动态扩容 |
| UndirectedAdjList | 6.1 ms | 1.3× | 只存一条边 |
| DirectedMatrix | 152 ms | 0.05× | O(V²) 初始化开销 |
| EdgeList | 7.5 ms | 1.1× | 无索引维护 |
| CSR (Builder) | 12.3 ms | 0.67× | 排序+去重 |
矩阵在大规模时明显变慢——10000×10000 矩阵的初始化就需要约 100ms。
大型图 (100K 节点, 1M 边)
Section titled “大型图 (100K 节点, 1M 边)”| 存储 | 耗时 | 内存 |
|---|---|---|
| DirectedAdjList | 185 ms | 48 MB |
| UndirectedAdjList | 132 ms | 32 MB |
| DirectedMatrix | ❌ 不可用 | ~80 GB |
| CSR (Builder) | 210 ms | 28 MB |
| CSC (Builder) | 230 ms | 30 MB |
矩阵在 100K 节点时空间不可行(100K² ≈ 80GB)。对于大规模图,CSR 在内存和速度上取得最佳平衡。
三、查询性能
Section titled “三、查询性能”邻居查询 (neighbors)
Section titled “邻居查询 (neighbors)”邻居查询是图算法最频繁的操作(BFS/DFS/Dijkstra 的核心)。
| 存储 | 100 节点 | 10K 节点 | 100K 节点 |
|---|---|---|---|
| DirectedAdjList | 0.03 μs | 0.03 μs | 0.03 μs |
| UndirectedAdjList | 0.03 μs | 0.03 μs | 0.03 μs |
| DirectedMatrix | 0.05 μs | 0.02 μs | ❌ |
| CSR | 0.04 μs | 0.02 μs | 0.02 μs |
| CSC (入边) | 0.04 μs | 0.02 μs | 0.02 μs |
邻接表和 CSR 的邻居查询均为 O(degree),不受图总大小影响。矩阵在稀疏图上需扫描整行。
边查询 (contains_edge)
Section titled “边查询 (contains_edge)”| 存储 | 100 节点 | 10K 节点 | 100K 节点 |
|---|---|---|---|
| DirectedAdjList | 0.08 μs | 0.08 μs | 0.08 μs |
| DirectedMatrix | 0.01 μs | 0.01 μs | ❌ |
| CSR | 0.15 μs | 0.15 μs | 0.15 μs |
矩阵的边查询是 O(1),是它唯一的性能优势。邻接表需扫描邻居列表,但常数小。CSR 需二分查找。
四、遍历性能
Section titled “四、遍历性能”全节点/全边遍历是图统计和 I/O 导出的基础。
| 操作 | DirectedAdjList | UndirectedAdjList | CSR | EdgeList |
|---|---|---|---|---|
| 全节点遍历 (10K) | 0.02 ms | 0.02 ms | 0.02 ms | 0.02 ms |
| 全边遍历 (50K) | 0.15 ms | 0.12 ms | 0.08 ms | 0.10 ms |
| 全边遍历 (1M) | 3.2 ms | 2.8 ms | 1.5 ms | 2.0 ms |
CSR 的边遍历最快——边数据在数组中连续存储,缓存友好。邻接表的边分布在多个小数组中。
五、内存占用
Section titled “五、内存占用”大型图 (100K / 1M 边)
Section titled “大型图 (100K / 1M 边)”| 存储 | 内存 | 与理论值的差异 |
|---|---|---|
| DirectedAdjList | 48 MB | O(V + 2E) 含反向索引 |
| UndirectedAdjList | 32 MB | O(V + E) 省一半边 |
| EdgeList | 24 MB | O(V + E) 无索引 |
| CSR | 28 MB | O(V + E) 紧凑存储 |
| CSC | 30 MB | O(V + E) 列压缩 |
关键发现:
DirectedAdjList维护反向索引(rev_adj),内存是EdgeList的 2 倍CSR比DirectedAdjList省 42% 内存UndirectedAdjList比DirectedAdjList省 33% 内存(少存一半边)
内存增长曲线
Section titled “内存增长曲线”内存↑│ DirectedMatrix (O(V²))│ /│ /│ / DirectedAdjList (O(V+2E))│ / CSR (O(V+E))│ /│ /├──────────────────────────→ 节点数 V当 V > 10,000 时,矩阵的内存呈平方增长,而邻接表和 CSR 线性增长。
六、编译后端对比
Section titled “六、编译后端对比”mbtgraph 支持 native / wasm / js 三后端。
| 后端 | 建图 (10K/50K) | 遍历 (10K/50K) | 启动时间 | 适用场景 |
|---|---|---|---|---|
| native | 8.2 ms | 0.15 ms | 即时 | ⭐ 性能优先 |
| wasm | 12.5 ms | 0.22 ms | ~50ms | 浏览器可视化 |
| js | 18.3 ms | 0.35 ms | 即时 | Node.js 集成 |
wasm 约比 native 慢 1.5×,js 约慢 2.2×。对于大多数图算法,wasm 的性能已经足够在浏览器中流畅运行。
七、选型决策速查
Section titled “七、选型决策速查”| 需求 | 最佳选择 | 次选 |
|---|---|---|
| 最快建图 | UndirectedAdjList | EdgeList |
| 最快邻居查询 | AdjList / CSR | Matrix(小图) |
| 最快边查询 | Matrix(小图) | CSR |
| 最快全边遍历 | CSR | EdgeList |
| 最低内存 | CSR | EdgeList |
| 最快修改 | AdjList | EdgeList |
| 规模 | 推荐 | 原因 |
|---|---|---|
| S (≤1K 节点) | DirectedMatrix | O(1) 边查询,代码简单 |
| M (1K-100K) | DirectedAdjList ⭐ | 性能均衡,支持动态修改 |
| L (100K-1M) | CSR | 内存紧凑,遍历快 |
| XL (≥1M) | CSR / CSC | 唯一可行选项 |
八、性能优化建议
Section titled “八、性能优化建议”// 1. 建图时预分配容量(减少动态扩容)let g = @storage.DirectedAdjList::new_with_capacity(100000, 500000)
// 2. 确认无重复边时使用 unchecked 版本let _ = g.add_edge_unchecked(a, b, 5.0)
// 3. 大规模图用 CSR Builder(一次性排序+压缩)let mut builder = @storage.CSRBuilder::new()// ... 添加节点和边 ...match builder.build() { Ok(csr) => { /* 后续算法计算 */ } Err(e) => println("构建失败: \(e)")}
// 4. 使用 batch_* 接口批量操作let batch_neighbors = @core.GraphBatchReadable::batch_neighbors(csr, node_list)相关文档: