私はまだOCamlの学習の初期段階にあり、OCamlのジェネリックコードから最大のパフォーマンスを引き出すための最良の方法が何であるかを知りたいと思っています。
小さな実験として、2つのポリモーフィック関数を作成しました。1つはC ++で、もう1つは特定の配列で最大の要素を見つけるOCamlで作成しました。
私が観察したことは、C ++ではこの種の抽象化に対してペナルティを支払わないのに対し、OCamlでのペナルティはパフォーマンスの大幅な低下です。余談ですが、私がすぐに作成したC ++ソリューションは、OCamlソリューションよりも一般的ですが、それは主に言語の経験がないことによるものです。
私の質問は次のとおりです:私が今観察した巨大なパフォーマンスペナルティを支払うことなく、OCamlでポリモーフィック関数を記述して使用する方法は?
この特定の問題について私が観察したもう1つのことは、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ビットで、Ubuntux6411.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
ただし、関数を「オーバーロード」してintとfloatを区別すると、プログラムのパフォーマンスは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