Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/391.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 番石榴集。性能不好_Java_Performance_Collections_Set_Guava - Fatal编程技术网

Java 番石榴集。性能不好

Java 番石榴集。性能不好,java,performance,collections,set,guava,Java,Performance,Collections,Set,Guava,我今天在生产中遇到了一个奇怪的问题。虽然我喜欢番石榴,但我遇到了一个用例,其中番石榴的Sets.intersection()的性能非常差。我已经编写了一个示例代码: Set<Long> cache = new HashSet<>(); for (long i = 0; i < 1000000; i++) { cache.add(i); } Set<Long> keys = new HashSet<>(); for (long i =

我今天在生产中遇到了一个奇怪的问题。虽然我喜欢番石榴,但我遇到了一个用例,其中番石榴的
Sets.intersection()
的性能非常差。我已经编写了一个示例代码:

Set<Long> cache = new HashSet<>();
for (long i = 0; i < 1000000; i++) {
    cache.add(i);
}
Set<Long> keys = new HashSet<>();
for (long i = 0; i < 100; i++) {
    keys.add(i);
}
long start = System.currentTimeMillis();
Set<Long> foundKeys = new HashSet<>();
for (Long key : keys) {
    if (cache.contains(key)) {
        foundKeys.add(key);
    }
}
System.out.println("Java search: " + (System.currentTimeMillis() - start));
start = System.currentTimeMillis();
SetView<Long> intersection = Sets.intersection(keys, cache);
System.out.println("Guava search: " + (System.currentTimeMillis() - start));

有人能告诉我为什么这不适合我的用例,或者番石榴中有bug吗?

事实证明,问题是多次调用了
SetView.size()
。由于
SetView
是两组交叉点的(实时)视图,因此每次都需要重新计算交叉点大小

public static <E> SetView<E> intersection( final Set<E> set1, final Set<?> set2) {
//...
  return new SetView<E>() {
    @Override public Iterator<E> iterator() {
      return Iterators.filter(set1.iterator(), inSet2);
    }
    @Override public int size() {
      return Iterators.size(iterator());
    }
    //...
  };
}
公共静态集合视图交叉点(最终集合集合集合1,最终集合集合集合2){
//...
返回新的SetView(){
@重写公共迭代器迭代器(){
返回Iterators.filter(set1.iterator(),inSet2);
}
@重写公共整型大小(){
返回Iterators.size(iterator());
}
//...
};
}
从这里可以看到,在这种情况下,重新计算意味着在整个视图中进行迭代,这可能非常耗时


因此,解决此问题的方法是确保只调用一次
size()
,并存储该值(如果您知道基础集不会更改),或者如果不可能,则通过
ImmutableSet.copyOf()
(例如)创建交叉点的副本。

请查看是,Guava实现恰好是不对称的:如果第一个集合比第二个集合大得多,那么速度就会慢得多。尝试切换这两个集合。是的,我的第一个集合已经小得多。@Mr.White在这种情况下,请参见第一条注释:)@Mr.White在生产中可能发生的情况,我们在这里看不到的是,
size()
经常在集合中被调用。由于返回的交集只是两个基础集的实时视图,
size()
在每次调用时都会重新计算。出于类似的原因,当视图处于活动状态时,两个原始集不会被垃圾收集,如果系统处于重载状态,这可能会导致显著的速度减慢。但这些只是猜测而已。实际上,您应该在整个应用程序的运行实例上附加一个探查器,以收集一些实际数据。如果我们传递的第一个集合更大,那么只有我们在size()方面遇到了问题,否则它似乎工作正常。请注意,
SetView
本身有一个
immutableCopy()
方法返回一个
ImmutableSet
@ColinD-Hmm,我不知道,听起来很有用。谢谢你的提示。
public static <E> SetView<E> intersection( final Set<E> set1, final Set<?> set2) {
//...
  return new SetView<E>() {
    @Override public Iterator<E> iterator() {
      return Iterators.filter(set1.iterator(), inSet2);
    }
    @Override public int size() {
      return Iterators.size(iterator());
    }
    //...
  };
}