如何在Java中并行化循环
在下面的代码中,对HashSet的每个元素调用一个本地方法。如果它返回一个特殊值,我们就停止循环。否则,我们将每个返回值添加到一个新的HashSet如何在Java中并行化循环,java,multithreading,java-threads,Java,Multithreading,Java Threads,在下面的代码中,对HashSet的每个元素调用一个本地方法。如果它返回一个特殊值,我们就停止循环。否则,我们将每个返回值添加到一个新的HashSet HashSet<Object> myHashSet=…; HashSet<Object> mySecondHashSet=…; for (Object s : myHashSet) { Object value = my_method(s); if(value==specialValue)
HashSet<Object> myHashSet=…;
HashSet<Object> mySecondHashSet=…;
for (Object s : myHashSet) {
Object value = my_method(s);
if(value==specialValue)
return value;
else
mySecondHashSet.add(value);
}
HashSet myHashSet=…;
HashSet mySecondHashSet=…;
用于(对象s:myHashSet){
对象值=我的方法;
如果(值==特殊值)
返回值;
其他的
添加(值);
}
我想把这个过程简化。HashSet中没有一个对象有任何共同的对象(它是一个树状结构),因此我知道它们可以在没有任何同步问题的情况下运行。我如何修改代码,使我的_方法的每次调用都开始一个新的步骤,并且如果其中一个线程的计算结果为特殊值,则所有线程都停止而不返回,并且返回特殊值 考虑到java 8,这可能相对简单,但不会保留初始代码语义: 在这种情况下,您所需要的是返回特殊值,一旦你击中它
if (myHashSet.parallelStream()
.map(x -> method(x))
.anyMatch(x -> x == specialValue)) {
return specialValue;
}
如果您需要保留转换后的值直到满足特殊值,那么您已经在注释中从@Elliot得到了答案,同时需要指出语义与原始代码不同,因为不会保留任何订购者
虽然它尚未被检查,但我希望以下内容得到优化,并在达到所需的特殊值时停止:
if (myHashSet.parallelStream()
.anyMatch(x -> method(x) == specialValue)) {
return specialValue;
}
我会在两次过程中完成:
my_method
对值进行两次转换,您可以惰性地进行转换并将结果记录下来:
private class Memoized {
private Object value;
private Object transformed;
private Function<Object, Object> transform;
public Memoized(Object value, Function<Object, Object> transform) {
this.value = value;
}
public Object getTransformed() {
if (transformed == null) {
transformed = transform.apply(value);
}
return transformed;
}
}
私人课堂备忘{
私人客体价值;
私有客体转化;
私有功能转换;
公共记忆(对象值、功能转换){
这个值=值;
}
公共对象getTransformed(){
if(transformed==null){
转换=转换。应用(值);
}
收益转化;
}
}
然后您可以使用以下代码:
Set<Memoized> memoizeds =
myHashSet.stream() // no need to go parallel here
.map(o -> new Memoized(o, this::my_method))
.collect(Collectors.toSet());
Optional<Memoized> matching = memoized.parallelStream()
.filter(m -> m.getTransformed().equals(specialValue))
.findAny();
if (matching.isPresent()) {
return matching.get().getTransformed();
}
Set<Object> allTransformed =
memoized.parallelStream()
.map(m -> m.getTransformed())
.collect(Collectors.toSet());
设置备忘=
myHashSet.stream()//这里不需要并行
.map(o->new memonized(o,this::my_方法))
.collect(收集器.toSet());
可选匹配=memonized.parallelStream()
.filter(m->m.getTransformed().equals(specialValue))
.findAny();
if(匹配.isPresent()){
返回匹配的.get().getTransformed();
}
设置所有转换=
memonized.parallelStream()
.map(m->m.getTransformed())
.collect(收集器.toSet());
这并不完全是你想要的,因为这还不完全清楚;但是你想要像这样的东西吗?Set mySecondHashSet=myHashSet.stream().parallel().map(x->my_method(x)).collector(Collectors.toSet());if(mySecondHashSet.contains(specialValue)){return specialValue;}你的主张是什么“不需要同步"不正确。哈希集不是线程安全的;以并行方式插入它可能会丢失更新或损坏。如果要并行化,则需要插入到线程安全集,或收集到线程本地集并合并这些集。啊,好的,我的意思是,没有任何对象共享任何变量。我应该使用哈希集的instaed数据结构?这段代码是否会在包含特殊值后立即停止执行?不,不会。主要目标是什么?检查特殊值或存储所有值直到找到特殊值?还是两者都有?如果我找到特殊值,我不需要继续处理。因此,在找到它后立即停止更有效。Continuing可能会吃掉parralization带来的任何收益。是的,这是正确的,但是mySecondHashSet的原因是什么?使用并行方法,你可能会在串行方法之前找到特殊值。因为如果我没有找到特殊值,我需要保留它们。我明白了,我这里的主要目标确实是优化执行me。我不需要记忆,因为我可以确定,由于初始数组不包含重复项,因此不能计算两次相同的值。您错过了记忆的要点。这样可以避免对同一对象调用两次我的方法(值
)。第一次检查转换后的值是否与特殊值匹配,第二次检查创建集合时。我仍然需要在elementSet上进行两次检查,所以O(2n)。如果我不能从并行化中获得加速,我可能会保留for循环。不,你仍然没有抓住要点。由于记忆化,每个元素都是集合,最多只传递给我的_方法一次。我也不太明白你为什么认为不能从并行化中获得加速。你没有注意到这个解决方案吗使用并行流?我明白了。谢谢,我会实现这个。我想知道,哈希表的大小在执行过程中变化很大。你认为这个机器操作系统对于一个小表来说“太mcuh”了吗?我可以测试它的大小,并且只在大于一个大小的范围内使用它,对于较小的表使用for循环。