遗传算法中的适应度函数并行化

时间:2019-01-14 16:56:39

标签: java concurrency genetic-algorithm

我是Java的初学者,作为我的家庭作业,我应该为旅行商问题(here)发布的遗传算法解决方案实现并发。我们的目标是通过线程执行染色体评估。所以我的猜测是我必须重写这部分代码才能成为多线程:

// Gets the best tour in the population
public Tour getFittest() {
    Tour fittest = tours[0];
    // Loop through individuals to find fittest
    for (int i = 1; i < populationSize(); i++) {
        if (fittest.getFitness() <= getTour(i).getFitness()) {
            fittest = getTour(i);
        }
    }
    return fittest;
}

// Gets population size
public int populationSize() {
    return tours.length;
}

最初,我打算手动拆分Array beetwen线程,但我认为这不是解决该问题的最佳方法。因此,我进行了一些研究,每个人都建议使用并行流或ExecutorService。但是,即使我试图模仿其他线程中发布的示例,也无法同时使用这两种解决方案。所以我的问题是:在这种情况下,我该如何精确实施它们?哪个更快?

编辑:对不起,我忘记发布尝试过的解决方案。在这里:

public Tour getFittest() {
    Tour fittest = tours[0];
    synchronized (fittest) {
        final ExecutorService executor = Executors.newFixedThreadPool(4); 
        final List<Future<?>> futures = new ArrayList<>();
        for (int i = 1; i < populationSize(); i++) {
            Future<?> future = executor.submit((Runnable) () -> {
                if (fittest.getFitness() <= getTour(i).getFitness()) {
                    fittest = getTour(i);
                }
            });
            futures.add(future);
        }
        try {
            for (Future<?> future : futures) {
                future.get();
            }
        }catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }
    return fittest;
}
public int populationSize() {
    return tours.length;
}

但是,当尝试运行它时,我在行中收到“在封闭范围内定义的局部变量fi​​ttest必须是最终的或实际上是最终的”错误:

fittest = getTour(i);

而且我不知道它为什么会发生,或者如何解决它,因为在初始化它时添加final关键字并不能解决它。除此之外,我对在此解决方案中使用synced关键字有一些疑问。我相信要实现真正的多线程,由于各种线程共享资源,因此需要使用它。我对吗?遗憾的是,我没有保留使用流的尝试,但是我很难理解它的工作原理。

Edit2:通过添加两个解决方法,我设法“解决”了我的解决方案。目前,我的代码如下:

public Tour getFittest() {
    Tour fittest = tours[0];
    synchronized (fittest) {
        final ExecutorService executor = Executors.newFixedThreadPool(4); 
        final List<Future<?>> futures = new ArrayList<>();
        for (int i = 1; i < populationSize(); i++) {
            final Integer innerI = new Integer(i);
            Future<?> future = executor.submit((Runnable) () -> {
                if (fittest.getFitness() <= getTour(innerI).getFitness()) {
                    setFitness(innerI, fittest);
                    }
                }
            );
            futures.add(future);
        }
        try {
            for (Future<?> future : futures) {
                future.get();
            }
        }catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
        }
    return fittest;
}

public int populationSize() {
    return tours.length;
}

public Tour setFitness (int i, Tour fittest) {
        fittest = getTour(i);
        return fittest;
}

也就是说,在编译时有两个问题。程序运行的每秒内存使用率在不断提高,在大约十秒钟的时间内我的16GB RAM达到了最大值,而变量“ fittest”却完全没有改变。所以我想我还是在做错事。

1 个答案:

答案 0 :(得分:0)

这是我的蒸汽实现:

private static Tour getFittest(Tour[] tours){
    List<Map.Entry<Tour,Double>> lengths = new ArrayList<>();
    Arrays.stream(tours).parallel().forEach(t->lengths.add(new AbstractMap.SimpleEntry<Tour,Double>(t,t.getLength())));
    return Collections.min(lengths,Comparator.comparingDouble(Map.Entry::getValue)).getKey();
}

根据您的定义,进一步寻找可以是1衬套

    private static Tour getFittest(Tour[] tours) {

    return Arrays.stream(tours).parallel().map(t -> new AbstractMap.SimpleEntry<Tour, Double>(t, t.getLength()))
            .min(Comparator.comparingDouble(Map.Entry::getValue)).get().getKey();
}

在进一步查看之后,他们使用了.getFitness(),它是长度的倒数。如果使用它,则使用.max()作为过滤器。

审查后实际上甚至更好

 return Arrays.stream(tours).parallel()
            .min(Comparator.comparingDouble(Tour::getLength)).get();