Noch ein weiterer synthetischer Benchmark: Sieve of EratosthenesSchnelle BitArray in OCaml
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 (mit Jane Street's Core und Res Bibliotheken)
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
Ich war überrascht, dass OCaml-Version (nativ) ist etwa 13 mal langsamer als C++. Ich ersetzte Res.Bits
durch Core_extended.Bitarray
, aber es wurde ~ 18 mal langsamer. Warum ist es so langsam? Bietet OCaml keine schnellen Operationen für die Bit-Manipulation? Gibt es alternative schnelle Implementierung von Bit-Arrays?
Um es klar zu sagen: Ich komme aus der C++ Welt und halte OCaml für eine mögliche Alternative zum Schreiben von leistungskritischem Code. Eigentlich bin ich mit solchen Ergebnissen etwas unheimlich.
EDIT:
Profilierungsergebnisse
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
...
Haben Sie den Code profiliert, um zu sehen, wo er seine Zeit verbringt? –
Ja. Ich bin noch nicht gut genug in OCaml, aber gprof sagte, das Programm verbringe die meiste Zeit mit Bit-Array-Manipulation. Ich habe versucht, Bit-Array mit regulären Array zu ersetzen und es wurde nur 3,3 mal langsamer als C++. Offensichtlich ist Bit-Array dort ein Flaschenhals. – Stas
Für Compiler-Autoren ist das Generieren von performancekritischem Code nicht einfach und am schlechtesten, die meisten Compiler-Hersteller (außer den Jungs von Clang) wollen es auf ihre Art machen :-(. Meine Meinung: für leistungskritischen Code heutzutage (in dieser Reihenfolge)) zu: C++, (füge hier Java und Fortran ein, wenn du jung sterben willst), Javascript (aber lies den Optimierungsleitfaden), Haskell mit Ghc ... Anständig, aber nicht ganz da: meistens alle anderen weder LLVM noch Microsoft/Google Auch Microsoft und Googles Budget stellen keine Garantie dar. – dsign