简体   繁体   English

如何在Java中并行化循环

[英]How to parallelize a loop in Java

In the following code, a local method is called on every element of a HashSet. 在以下代码中,在HashSet的每个元素上调用一个本地方法。 If it returns a special value we halt the loop. 如果返回一个特殊值,我们将停止循环。 Otherwise we add every return value to a new HashSet. 否则,我们将每个返回值添加到新的HashSet中。

HashSet<Object> myHashSet=…; 
HashSet<Object> mySecondHashSet=…; 

for (Object s : myHashSet) {
    Object value = my_method(s);
    if(value==specialValue)
        return value; 
    else 
        mySecondHashSet.add(value);
 }

I'd like to parralelize this process. 我想将这个过程并行化。 None of the objects in the HashSet have any objects in common (it's a tree-like structure) so I know they can run without any synchonization issues. HashSet中的所有对象都没有任何共同的对象(这是树状结构),因此我知道它们可以运行而没有任何同步问题。 How do I modify the code such that each call of my_method(s) starts a new tread, and also that if one of the threads evaluates to the special values, all the threads halt without returning and the special value is returned? 如何修改代码,使my_method的每次调用开始一个新的过渡,并且如果一个线程的求值结果为特殊值,则所有线程都将暂停而不返回,并返回特殊值?

Having in mind java 8, this could be relatively simple, while it won't preserve your initial code semantics: 考虑到Java 8,这可能相对简单,但它不会保留您的初始代码语义:

In case all you need is to return special value once you hit it 万一您需要击中返回特殊值

if (myHashSet.parallelStream()
             .map(x -> method(x))
             .anyMatch(x -> x == specialValue)) {

    return specialValue;
}

If you need to keep transformed values until you meet the special value, you already got an answer from @Elliot in comments, while need to mention that semantic is not the same as your original code, since no orderer will be preserved. 如果您需要保持转换后的值直到满足特殊值,您已经从@Elliot的注释中得到了答案,同时需要提及的是语义与原始代码不同,因为将不保留任何定序符。


While it yet to be checked, but I would expect following to be optimized and stop once it will hit wanted special value: 虽然尚待检查,但我希望可以优化以下内容,并在达到所需的特殊值时停止:

if (myHashSet.parallelStream()
             .anyMatch(x -> method(x) == specialValue)) {

    return specialValue;
}

I would do that in two passes: 我会分两步这样做:

  1. find if any of the transformed set elements matches the special value; 查找是否有任何变换后的set元素与特殊值匹配;
  2. transform them to a Set. 将它们转换为集合。

Starting a new thread for each transformation is way too heavy, and will bring your machine to its knees (unless you have very few elements, in which case parallelizing is probably not worth the effort. 为每个转换启动一个新线程太重了,并且会使您的机器瘫痪(除非您只有很少的元素,在这种情况下,并行化可能不值得付出努力。

To avoid transforming the values twice with my_method , you can do the transformation lazily and memoize the result: 为了避免使用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;
    }
}

And then you can use the following code: 然后可以使用以下代码:

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());

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM