【问题标题】:Parallelization of Genetic Algorithm Slowed Algorithm Significantly. Why would this be?遗传算法的并行化显着减慢了算法。为什么会这样?
【发布时间】:2012-06-14 19:17:23
【问题描述】:

我编写了一个遗传算法,为了优化它的性能,我决定对个人进行并行化的适应度测试。为了了解这对我的算法产生了什么样的改变,我重新进行了在并行化之前完成的测试运行,在该运行中我测试了 GA 在不断增长的人口规模下的性能。

GA 的并行版本实际上比原始版本长了大约 50%。我意识到有时并行化的开销实际上可能比它节省的时间更多,但我怀疑这是否应该适用于这种情况——我的适应度测试正在寻找 Sheckel 的 Foxholes 函数的全局最小值(http://extreme.adorio-research.org/download/mvf/html/node51.html),而我的人口规模从 10 到 1000 不等。我希望在并行执行 1000 次 sheckel 散兵坑时,节省的时间将大大超过并行化的开销。

所以我的问题是:为什么并行化会减慢算法的速度(并且如此显着)?

为了记录,我正在使用 Java 进行编码,并且我正在使用 CountDownLatch 进行并行化,该 CountDownLatch 在继续之前等待所有线程(适应性测试)执行。

【问题讨论】:

  • 你用的是什么CPU芯片?如果它是旧的单核,并行化将无济于事。也就是说,我发现英特尔 I3 上的良好并行确实可以提供几乎 2 倍的性能,正如人们所期望的那样。
  • 哈,我想到了它受到硬件限制的想法。我在一个较旧的双核上,所以我意识到并行化不会像我在更强大的机器上那样有效,但它仍然应该比串行执行更快。另外,我只是在双核上对其进行编程,当我完成后它实际上将被移至八核。
  • 听起来你应该提高一些速度。好的,还有两个“明显”的问题。你在做很多 I/O 吗?是否有任何资源同步/锁定?
  • 您是否同时运行 100 个线程?或者一些合理的东西,比如一次 4-8 个线程,例如使用 ExecutorService?
  • 创建一个新线程是一项昂贵的操作。如果您在每一代中重新创建线程,您将乞求性能降低。您应该只使用合理数量的线程(取决于内核数量)并重用您创建的线程。

标签: java performance parallel-processing genetic-algorithm


【解决方案1】:

根据您的 cmets,您的操作似乎相当合理,除了线程数。但是你提到你正在使用 CountDownLatch 让我思考......

我强烈建议您使用ExecutorService/Executors 代替您自己的代码进行并行化。将你的类设为Callable,创建一堆,然后调用invokeAll()。这样,训练有素(不确定他们是否高薪)的专家完成了大部分编码工作。

使用Executors,控制最大线程数很简单。您可以致电Runtime.availableProcessors() 了解一次运行多少线程,然后进行一些测试和调整。

编辑:刚刚发布了introduction to converting an algorithm to use ExecutorService.享受,欢迎 cmets/反馈。

【讨论】:

  • Hmmmmmm,似乎是一个合理的例外,尽管在我首先熟悉它之前我总是犹豫要实施任何东西。我绝对可以谷歌执行者,但正如你所建议的那样,你有什么推荐的读物我可以看吗?
  • 也许我会写一篇博文并给你发一个链接,但更安全的选择是花一点钱在 Goetz 等人的Java Concurrency in Practice 一书中.人。
  • 所以在做了一些阅读之后,我绝对认为 Executor 是要走的路 - 能够简单地在人口开始时创建线程并在每一代重用它们肯定会为我节省大量表现。而且,对于将来有兴趣阅读此主题的任何人,我发现这篇很棒的博客文章对理解 Executors 的工作方式非常有帮助:softwareengineeringsolutions.com/blogs/2010/07/21/…
【解决方案2】:

好的,答案是它并没有像您想象的那样并行化。问题是“为什么?”不看代码就很难得到答案。但有一些明显的地方值得一看:

  • 确保(你会讨厌这个)你为 Thread 使用了正确的入口点。保证您的线程将序列化并且不告诉您任何事情的一种方法是调用run() 方法而不是start() 方法。这听起来很傻,但我已经被这个咬了。

  • 使用例如 jconsole 确保线程完全同时运行。如果没有,你就意外锁定了某个东西。

  • 检查您同步的内容。检查您正在使用的集合类。其中一些根本不是线程安全的,其中一些是线程安全的,因为它们具有内部同步。线程之间共享的任何 Collection 类都可能是恶意软件。

  • 如果没有任何结果,请与同事一起在纸上完成代码执行,然后手写出线程。

【讨论】:

  • 谢谢,我会试试你的建议。
【解决方案3】:

所以我弄清楚了问题所在 - 我曾假设我的体能测试花费的时间足够长,以至于并行化是值得的,但事实并非如此。我填充了适应度测试,人为地延长了它(这只是我用来监控 GA 性能的测试适应度测试),我现在看到执行时间存在显着差异 - 现在人口规模的增长导致将执行时间延长 1000 秒,而不是 10 秒。我应该指出,这是在实施 Executor 之前,正如我们所建议的那样。

感谢大家的帮助!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-02-22
    • 2011-11-24
    • 2021-09-27
    • 2012-07-07
    • 1970-01-01
    • 2021-09-15
    • 1970-01-01
    • 2013-12-21
    相关资源
    最近更新 更多