Koloboke集合间复制的性能问题及优化方案咨询
优化Koloboke集合复制性能的方案
当然有办法提升第二个集合的填充性能!咱们先拆解下问题:你当前用LongCursor逐个调用add()的方式,每一次添加都可能触发集合的扩容检查,当集合规模很大时,这种频繁的小操作累积起来就会导致性能低下。下面是几个实用的优化方案,覆盖不同场景:
1. 直接使用批量添加API(首选)
Koloboke的集合原生支持高效的批量操作,你完全不需要手动遍历cursor来逐个添加。直接调用addAll()方法传入源集合即可,内部会做针对性的优化(比如一次性分配足够的空间、减少扩容次数):
final HashLongSet set2 = HashLongSets.newMutableSet(); set2.addAll(set1);
如果是需要过滤元素的场景,你可以先把符合条件的元素批量收集到数组里,再一次性添加:
final HashLongSet set2 = HashLongSets.newMutableSet(); // 先把源集合转成数组 long[] allElements = set1.toArray(); // 过滤后批量添加 List<Long> filtered = new ArrayList<>(); for (long elem : allElements) { if (elem > 0) { // 示例过滤条件 filtered.add(elem); } } // 转成基本类型数组再添加,避免装箱开销 long[] filteredArray = filtered.stream().mapToLong(Long::longValue).toArray(); set2.addAll(filteredArray);
2. 合理预估初始容量(折中方案)
如果没法提前知道最终要添加的元素数量,但能估算一个上限(比如源集合的大小就是最大可能值,即使有过滤也不会超过这个数),可以在创建set2时指定初始容量,避免频繁扩容:
// 用源集合的大小作为初始容量,即使后续有过滤,大一点的初始容量也不会有太大问题 final HashLongSet set2 = HashLongSets.newMutableSet(set1.size()); final LongCursor cursor = set1.cursor(); while (cursor.moveNext()) { // 这里可以加条件判断 if (cursor.elem() % 2 == 0) { set2.add(cursor.elem()); } } // 如果担心空间浪费,最后可以手动收缩集合 set2.trimToSize();
3. 用缓冲区分批添加(适合有复杂过滤的场景)
如果过滤逻辑比较复杂,没法一次性拿到所有符合条件的元素,可以用一个缓冲区数组来分批收集元素,达到一定数量就批量添加到目标集合,减少单次add()的开销:
final HashLongSet set2 = HashLongSets.newMutableSet(); final LongCursor cursor = set1.cursor(); // 定义一个合适大小的缓冲区(比如1024或4096,根据实际情况调整) long[] buffer = new long[4096]; int bufferIndex = 0; while (cursor.moveNext()) { long elem = cursor.elem(); // 你的条件判断逻辑 if (elem > 100000) { buffer[bufferIndex++] = elem; // 缓冲区满了就批量添加 if (bufferIndex == buffer.length) { set2.addAll(buffer); bufferIndex = 0; } } } // 添加缓冲区剩余的元素 if (bufferIndex > 0) { set2.addAll(Arrays.copyOf(buffer, bufferIndex)); }
这些方案都能有效减少扩容次数和方法调用的累积开销,相比原有的逐个添加方式,性能提升会非常明显。
内容的提问来源于stack exchange,提问作者Gaurav Agarwal
相关产品推荐
相关产品推荐

