我仍处于学习 OCaml 的早期阶段,我很想知道从 OCaml 中的通用代码中提取最大性能的最佳方法是什么。
作为一个小实验,我编写了两个多态函数:一个在 C++ 中,另一个在 OCaml 中,用于查找给定数组中的最大元素。
我观察到的是,虽然在 C++ 中你不会为这种抽象付出任何代价,但在 OCaml 中的代价是性能下降了一个数量级。顺便说一句,我快速编写的 C++ 解决方案比 OCaml 更通用,但我主要将其归咎于我对这门语言缺乏经验。
我的问题如下:如何在 OCaml 中编写和使用多态函数而不付出我刚刚观察到的巨大性能损失?
对于这个特定问题,我观察到的另一件事是,我在 OCaml 中的函数式解决方案比命令式解决方案慢,而 C++ 中的“函数式”解决方案与模拟命令式方法相比没有受到任何惩罚。
C++ 代码g++ -std="c++0x" -O3 -o max_cpp max.cpp
使用 gcc-4.6.3 编译,OCaml 代码使用:ocamlopt -o max_ml max.ml
使用 ocamlopt 版本 3.12.1。生成的两个可执行文件都是 32 位并在 Ubuntu x64 11.04 上运行
我提交了两个程序的代码。
C++ 代码(当然不完全安全;))
#include <iostream>
#include <vector>
#include <numeric>
template <typename T> T max (T a, T b) {
return (a>b)? a : b;
}
template <typename I> typename I::value_type find_max (I begin, I end) {
auto max = *begin;
for (begin++;begin!=end;begin++)
if (*begin > max) max = *begin;
return max;
}
template <typename I> typename I::value_type find_max1(I begin, I end) {
return std::accumulate(begin, end, *begin, max< typename I::value_type> );
}
int main(int argc, char ** argv) {
const size_t nElem = atoi(argv[1]);
const size_t nIter = atoi(argv[2]);
std::vector<int> intA(nElem);
std::vector<double> dubA(nElem);
for (int i=0;i<nIter;i++) {
auto res1 = find_max(intA.begin(), intA.end());
auto res2 = find_max(dubA.begin(), dubA.end());
std::cout << "Max int: " << res1 << " " << "Max dub: " << res2 << std::endl;
}
}
OCaml 代码
let max a b = if a > b then a else b
(* functional version *)
let find_max vector =
Array.fold_right max vector vector.(0)
(* imperative version *)
let find_max1 vector =
let length = Array.length vector in
let max = ref (vector.(0)) in
for i=1 to length-1 do
if vector.(i) > !max then max := vector.(i)
done; max
let nElems = int_of_string Sys.argv.(1)
let nIter = int_of_string Sys.argv.(2)
let _ = let intA = Array.make nElems 0 in
let dubA = Array.make nElems 0.0 in
for i=1 to nIter do
let res1 = find_max intA in
let res2 = find_max dubA in
print_int !res1;
print_newline ();
print_float !res2;
done
但是,如果我“重载”函数来区分整数和浮点数,那么程序的性能甚至超过我的 C++ 代码的 50%!我想知道为什么。
let find_max_int (vector : int array) =
let length = Array.length vector in
let max = ref (vector.(0)) in
for i=1 to length-1 do
if vector.(i) > !max then max := vector.(i)
done; max
let find_max_float (vector : float array) =
let length = Array.length vector in
let max = ref (vector.(0)) in
for i=1 to length-1 do
if vector.(i) > !max then max := vector.(i)
done; max
时间安排相当粗略地执行:
time ./max_cpp 1000000 100
和 time ./max_ml 1000000 100