【发布时间】:2013-01-21 19:08:53
【问题描述】:
另一个综合基准:Sieve of Eratosthenes
C++
#include <vector>
#include <cmath>
void find_primes(int n, std::vector<int>& out)
{
std::vector<bool> is_prime(n + 1, true);
int last = sqrt(n);
for (int i = 2; i <= last; ++i)
{
if (is_prime[i])
{
for (int j = i * i; j <= n; j += i)
{
is_prime[j] = false;
}
}
}
for (unsigned i = 2; i < is_prime.size(); ++i)
{
if (is_prime[i])
{
out.push_back(i);
}
}
}
OCaml(使用 Jane Street's Core 和 Res 库)
open Core.Std
module Bits = Res.Bits
module Vect = Res.Array
let find_primes n =
let is_prime = Bits.make (n + 1) true in
let last = float n |! sqrt |! Float.iround_exn ~dir:`Zero in
for i = 2 to last do
if not (Bits.get is_prime i) then () else begin
let j = ref (i * i) in
while !j <= n; do
Bits.set is_prime !j false;
j := !j + i;
done;
end;
done;
let ar = Vect.empty () in
for i = 2 to n do
if Bits.get is_prime i then Vect.add_one ar i else ()
done;
ar
我很惊讶 OCaml 版本(本机)比 C++ 慢 13 倍。我用Core_extended.Bitarray 替换了Res.Bits,但速度变慢了~18 倍。为什么这么慢? OCaml 不为位操作提供快速操作吗?有没有其他快速实现位数组的方法?
明确一点:我来自 C++ 世界,并认为 OCaml 作为编写性能关键代码的可能替代方案。其实这样的结果我有点害怕。
编辑:
分析结果
Each sample counts as 0.01 seconds.
% cumulative self self total
time seconds seconds calls ms/call ms/call name
50.81 1.26 1.26 camlRes__pos_1113
9.72 1.50 0.24 camlRes__unsafe_get_1117
6.68 1.66 0.17 camlRes__unsafe_set_1122
6.28 1.82 0.16 camlNopres_impl__set_1054
6.07 1.97 0.15 camlNopres_impl__get_1051
5.47 2.10 0.14 47786824 0.00 0.00 caml_apply3
3.64 2.19 0.09 22106943 0.00 0.00 caml_apply2
2.43 2.25 0.06 817003 0.00 0.00 caml_oldify_one
2.02 2.30 0.05 1 50.00 265.14 camlPrimes__find_primes_64139
1.21 2.33 0.03 camlRes__unsafe_get_1041
...
【问题讨论】:
-
您是否对代码进行了概要分析以查看它在哪里花费时间?
-
是的。我在 OCaml 方面还不够好,但 gprof 说该程序大部分时间都花在位数组操作上。我尝试用常规数组替换位数组,它只比 C++ 慢 3.3 倍。显然位数组是一个瓶颈。
-
对于编译器编写者来说,生成性能关键代码并不容易,而且最糟糕的是,大多数编译器制造商(除了 Clang 的人)都希望按照自己的方式进行 :-( 。我的意见:对于性能关键代码这些天坚持(按此顺序):C++,(如果你想年轻就死,在这里插入 Java 和 Fortran),Javascript(但请阅读优化指南),带有 Ghc 的 Haskell ......体面但不完全在那里:大多数其他人都没有使用 LLVM,也没有微软/谷歌的预算。实际上,微软和谷歌的预算也不是保证。
-
听起来很像。我很确定它可以通过更好地实现位操作优化来解决[或类似的东西]。但是我什至在 OCaml 上都达不到您的水平-我几乎看不懂您发布的代码-只是想确保您在尝试查找问题时正在查看正确的内容,在查找时“猜错”并不罕见代码慢的地方。
-
并不是说它对性能很重要,但是你编写了奇怪的 Ocaml 代码。你知道你可以在条件语句中省略
else,只要它的类型是unit?所以没有必要写else ()。我尝试使用Bigarray,但它给出的结果比gasche 的字符串解决方案稍慢。哦,那个sqrt也很讨厌,它引入了不必要的数字错误(对于足够大的n)。
标签: c++ performance algorithm ocaml bitarray