性能优化技巧
选择合适的存储
Section titled “选择合适的存储”// ❌ 默认选择(可能不是最优)let g = @storage.new_directed()
// ✅ 根据场景选择// 稀疏图 → AdjListlet g = @storage.new_directed()
// 稠密图 → Matrixlet g = @storage.new_directed_matrix(capacity)
// 大规模静态图 → CSRlet csr = @storage.to_csr(g)// ❌ 逐个添加边let _ = @core.GraphWritable::add_edge(g, n0, n1, 1.0)let _ = @core.GraphWritable::add_edge(g, n1, n2, 2.0)let _ = @core.GraphWritable::add_edge(g, n2, n3, 3.0)
// ✅ 使用批量添加let edges = [(n0, n1, 1.0), (n1, n2, 2.0), (n2, n3, 3.0)]let _ = @storage.DirectedAdjList::add_edges_batch(g, edges)
// ✅ 使用 CSR 批量查询let neighbors = @core.GraphBatchReadable::batch_neighbors(csr, [n0, n1, n2])// ❌ 动态扩容let g = @storage.new_directed()
// ✅ 预分配(已知规模时)let g = @storage.new_directed_matrix(1000) // 预分配 1000 节点// ❌ 重复计算let sp1 = @shortest_path.floyd_warshall(g)let sp2 = @shortest_path.floyd_warshall(g) // 重复!
// ✅ 预计算一次,多次查询let fw = @shortest_path.floyd_warshall(g)let dist_a = fw.distance(n0, n1)let dist_b = fw.distance(n2, n3)选择合适算法
Section titled “选择合适算法”// ❌ 用复杂算法解决简单问题let sp = @shortest_path.floyd_warshall(g) // O(V³)
// ✅ 根据需求选择// 单源最短路径let sp = @shortest_path.dijkstra(g, source) // O((V+E)logV)
// 两节点间最短路径let path = @shortest_path.dijkstra_targeted(g, source, target)
// 无权图最短路径let path = @traversal.bfs_shortest_path(g, source, target) // O(V+E)避免不必要的转换
Section titled “避免不必要的转换”// ❌ 频繁转换for node in nodes { let adj = @storage.to_directed_adj_list(g) // 每次循环都转换! // 处理...}
// ✅ 一次转换let adj = @storage.to_directed_adj_list(g)for node in nodes { // 使用 adj}使用 UndirectedAdjList
Section titled “使用 UndirectedAdjList”// ❌ 无向图用有向存储let g = @storage.new_directed() // 存储双向边,空间翻倍
// ✅ 专用无向存储let g = @storage.new_undirected() // 半存储,节省 50%只读场景用 CSR
Section titled “只读场景用 CSR”// ❌ 动态存储用于只读分析let g = @storage.new_directed()// ... 构建图let result = @pagerank.pagerank(g, ...) // 频繁遍历
// ✅ 转为 CSR 优化遍历let csr = @storage.to_csr(g)let result = @pagerank.pagerank(csr, ...) // 缓存友好// 可并行的任务let result1 = @shortest_path.dijkstra(g, source1)let result2 = @shortest_path.dijkstra(g, source2)// 两个计算相互独立,可并行// ❌ 逐个查询for node in nodes { let sp = @shortest_path.dijkstra(g, node) // 处理...}
// ✅ CSR 批量查询let neighbors = @core.GraphBatchReadable::batch_neighbors(csr, nodes)常见操作耗时参考
Section titled “常见操作耗时参考”| 操作 | 1K 节点 | 10K 节点 | 100K 节点 |
|---|---|---|---|
| BFS | < 1ms | ~5ms | ~50ms |
| Dijkstra | < 1ms | ~10ms | ~100ms |
| Floyd-Warshall | ~10ms | ~10s | N/A |
| PageRank | < 1ms | ~10ms | ~100ms |
| Louvain | < 1ms | ~5ms | ~50ms |
| 算法 | 时间复杂度 | 适用规模 |
|---|---|---|
| BFS/DFS | O(V+E) | 通用 |
| Dijkstra | O((V+E)logV) | 非负权图 |
| Floyd-Warshall | O(V³) | V < 1000 |
| Kruskal | O(ElogE) | 稀疏图 |
| Prim | O((V+E)logV) | 稠密图 |
| Dinic | O(V²E) | 网络流 |
| Louvain | O(nlogn) | 社区检测 |
1. 忽略深拷贝
Section titled “1. 忽略深拷贝”// ❌ 直接修改输入let result = some_algorithm(g, ...) // g 可能被修改
// ✅ 深拷贝后操作let g_copy = @storage.to_directed_adj_list(g)let result = some_algorithm(g_copy, ...)2. 链式赋值
Section titled “2. 链式赋值”// ❌ 忽略返回值@core.GraphWritable::add_edge(g, n0, n1, 1.0) // 警告!
// ✅ 消费返回值let _ = @core.GraphWritable::add_edge(g, n0, n1, 1.0)
// ✅ 链式调用let net = FlowNetwork::new(4)let net = net.add_edge(0, 1, 16.0)3. 错误处理
Section titled “3. 错误处理”// ❌ 忽略错误let _ = @core.GraphWritable::add_edge(g, n0, n1, 1.0)
// ✅ 处理错误match @core.GraphWritable::add_edge(g, n0, n1, 1.0) { Ok(()) => () Err(e) => handle_error(e)}