基准测试与性能分析遗传算法
学习如何在遗传算法优化中使用基准测试和性能分析。
探索 BEAM
到目前为止,我们无需过多关注所实现算法的性能。因为解决方案规模较小,且处理的种群也相对有限,因此效率问题并未成为关注重点。然而,在现实世界中,将遗传算法应用于实际问题时,我们通常需要应对更大规模的解和种群。
事实上,Elixir 这门语言并非为高计算密集型任务设计,其在浮点运算、数学计算和矩阵乘法等方面表现较慢。这是因为 Elixir 运行在 BEAM 虚拟机上,而 BEAM 最初是为电信系统设计的。这并不意味着我们无法在 Elixir 中编写高效的遗传算法;而是意味着我们必须有意识地对这些算法进行优化。
BEAM 是 Erlang 虚拟机,也是 Erlang/OTP 的核心。每个 Elixir 文件都会被编译为 BEAM 字节码。要真正理解应用程序的性能,关键在于了解代码编译后在 BEAM 上运行时发生了什么。本章将简要介绍 BEAM 的一些特性,但内容并不全面。
在本章中,我们将学习如何对算法进行基准测试和性能分析,并初步了解性能真正重要的场景。此外,我们还将学习多种优化算法的方法。接下来,我们将按以下顺序逐步进行一系列优化:
- 创建基准测试并分析算法性能
- 优化 Elixir 代码的性能
- 并行化算法
- 编写 NIFs(本地接口函数)
在实施优化时,通常遵循上述顺序,只有在确实必要时才进入下一步。
什么是基准测试与性能分析?
任何优化过程的第一步都是开展调查工作,建立基线并确定代码中的性能瓶颈。基准测试 是从性能角度评估代码的过程。它通常用于衡量代码在内存使用(空间)或执行时间(时间)方面的表现。
性能分析 是对程序在空间或时间维度上的特定方面进行评估,以辅助性能优化。性能分析有助于识别代码中的具体瓶颈。
基准测试与性能分析之间的区别较为微妙。基准测试的目的是为整个操作建立性能指标,以便在不同操作之间进行比较。例如,可以比较不同设置下的操作性能,或在不同硬件上运行相同操作的性能差异。
性能分析的目的是深入理解程序的行为。例如,性能分析工具可能指出程序大部分时间消耗在哪些部分,或者哪些函数被调用最多。性能分析能提供关于代码优化优先级的详细洞察。
我们可以使用多种工具来对代码进行基准测试和性能分析。在接下来的几节课中,我们将使用 Benchee 进行基准测试,使用 ExProf 进行性能分析。但在开始优化之前,我们需要先判断是否真的值得进行优化。
决定何时进行优化
程序员常常过早且不必要地决定优化代码。优化本身并无问题,但如果时机不对或动机不当,反而会阻碍开发进程。
实际的遗传算法具有较高的计算成本;真实世界的问题往往涉及大量数据。幸运的是,现代硬件已经大大缓解了软件必须高度优化的压力。在许多情况下,可用的计算能力远超实际需求,此时优化并非必需。
当然,当处理大量数据时,优化可能是必要的,以防止算法因资源耗尽而崩溃。
在一台中等性能的机器上,当种群规模与每个染色体的大小相乘达到约一百万时,遗传算法的运行速度会明显变慢。在大多数其他情况下,性能下降并不明显,此时优化并无必要。