考虑一组对象和一组谓词,它们是形成谓词对象对集合的最快方法,其中每一对都是一个对象,一个谓词返回true。
对象在对中必须是唯一的,但这不适用于谓词。
即。考虑对象A,B和C,以及谓词P1,P2,P3
然而,(A,P1),(B,P1),(C,P2)是有效的一对对 (A,P1),(A,P1),(C,P2)无效,因为对中有重复的对象
因此,一旦谓词与某个对象匹配,它就会有效地拥有它。
即。鉴于上述限制,最快的方法是实现下面的方法:
Collection<Pair<Object,Predicate<Object>> getAllMatches(Collection<Object> objects, Collection<Predicate<Object>>);
其中Pair是:
class Pair<A,B> {
A a;
B b;
}
我知道我需要使用多线程,但我不确定要使用的最佳策略或最佳集合实现。此外,我认为由于需要某种锁定或所有权机制,唯一性约束将引入争用。
继承我的尝试,似乎是基本的,肯定必须有更快的方式:
Collection<Pair<Object,Predicate> getAllMatches(BlockingQueue<Object> objects, Collection<Predicate> predicates){
List<Callable<Pair>> callables = new ArrayList<>();
for (Object o : objects){
Callable<Pair> c = ()-> {
Object polled = objects.take();
for (Predicate p : predicates){
if (p.test(polled)){
return new Pair<Object,Predicate>(o,p);
}
}
objects.put(o);
return null;
}
callables.add(c);
}
List<Future<Pair>> futurePairs = exectors.invokeAll(callables);
// return pairs
}
答案 0 :(得分:3)
您的基准应该绝对是:
final Collection<Pair<Object, Predicate>> getMatches(
final Collection<Object> objects,
final Collection<Predicate> predicates) {
final Set<Pair<Object, Predicate>> matches = new HashSet<>();
for (Object o : objects) {
for (Predicate p : predicates) {
if (p.test(o)) {
matches.add(Pair.with(o, p));
break;
}
}
}
return matches;
}
顺序执行通常最快。这看似违反直觉 - 在多个内核上运行测试应该最快 - 但对于许多操作而言,您的瓶颈实际上是内存访问。每个处理器都会停止运行,什么都不做,同时验证它的处理器级缓存是否与所有其他处理器的缓存一致。
如果您确信多线程可以为您节省一些时间,我建议测试这样的事情:
final Collection<Pair<Object, Predicate>> getMatches(
final Collection<Object> objects,
final Collection<Predicate> predicates) {
final List<Future<Pair<Object,Predicate>>> futures = new ArrayList<>();
for (final Object o : objects) {
futures.add(executorService.invoke(() -> {
for (Predicate p : predicates) {
if (p.test(o)) {
return Pair.with(o, p);
}
}
return null;
});
}
final Collection<Pair<Object,Predicate>> matches = new ArrayList<>(futures.size());
for (final Future<Pair<Object,Predicate>> future : futures) {
final Pair<Object,Predicate> pair = future.get();
if (pair != null) {
matches.add(pair);
}
}
return matches;
}
没有任何线程写到共享内存,所以没有锁争用担心。
答案 1 :(得分:1)
我想你可能会有点过分复杂。流对象和每个对象都会找到与之匹配的谓词:
objects.stream() // or parallelStream() for multithreaded
.distinct() // can omit this if uniqueness of objects is enforced elsewhere
.flatMap(obj -> predicates.stream()
.filter(p -> p.test(obj))
.map(p -> new Pair<>(obj, p))
.limit(1) // one predicate per object
).collect(toList());
答案 2 :(得分:0)
使用声明性并行性的Java8流的简短解决方案:
Collection<Pair<Object, Predicate<Object>>> getAllMatches(Set<Object> objects, Set<Predicate<Object>> predicates) {
List<Pair<Object, Predicate<Object>>> pairs = predicates.parallelStream()
.map(predicate -> new Pair<>(objects.stream().filter(predicate), predicate))
.flatMap(pair -> pair.a.map(a -> new Pair<>(a, pair.b)))
.collect(toList());
return pairs;
}
并行执行由流管理:
List<Pair<Object, Predicate<Object>>> pairs = predicates.parallelStream()
下一行创建一个Pair(该流包含所有匹配的对象):
.map(predicate -> new Pair<>(objects.stream().filter(predicate), predicate))
下一行展平为配对:
.flatMap(pair -> pair.a.map(a -> new Pair<>(a, pair.b)))
最后一行创建最终集合:
.collect(toList());
如果objects
或predicates
不重复,请将.distinct()
置于stream()
或parallelStream()
之后。