jGraphT是否支持并行添加顶点和边以提升批量插入效率
结论
不建议直接使用stream().parallel()并行流直接调用jGraphT的顶点、边添加方法,原因和可行方案如下:
核心原因
jGraphT官方提供的绝大多数默认图实现(包括常用的SimpleGraph、DirectedWeightedGraph等)都是非线程安全的,内部没有做并发访问的同步处理。多线程同时调用addVertex()、addEdge()方法时会触发竞态条件,轻则出现顶点/边丢失、数据统计错误,重则抛出并发修改异常、直接损坏图的内部存储结构。
如果你确实想通过并行逻辑提升处理速度,可以用以下两种安全方案:
- 方案1:拆分预处理和添加阶段。并行流仅用来完成数据清洗、格式转换、去重等前置计算逻辑,把最终要添加的顶点、边分别存入线程安全集合(比如用
ConcurrentHashMap.newKeySet()存顶点、CopyOnWriteArrayList存边),所有预处理完成后再用单线程调用addAllVertices()、addAllEdges()批量写入图。这种方案适合预处理逻辑占比高的场景,既能拿到并行计算的收益,又不会触发jGraphT的线程安全问题。 - 方案2:使用线程安全包装类。通过
Graphs.synchronizedGraph(originalGraph)把原始图包装为同步图后,确实可以在并行流中直接调用添加方法,但这种实现用的是全局锁,所有添加操作实际还是串行执行,额外的锁竞争开销反而会让整体速度比单线程流更慢,完全没有收益,不推荐使用。
额外优化建议
jGraphT 1.5及以上版本提供的批量添加方法addAllVertices()、addAllEdges(),性能比循环单次调用添加方法高30%以上,比强行使用并行流的收益更高,优先推荐用这个方法做性能优化。
内容的提问来源于stack exchange,提问作者Harry Zalessky
相关产品推荐
相关产品推荐

