[JAVA] Ist WebAssembly wirklich schnell? [Numerische Berechnung]

Es wird gesagt, dass die JS-Funktion WebAssembly die Berechnung beschleunigt, aber ich habe auch die Theorie gesehen, dass dies nicht der Fall ist, daher werde ich sie kurz überprüfen. Hier werde ich mich auf die Geschwindigkeit der reinen numerischen Berechnung konzentrieren, wie z. B. Dateigröße usw. Aspekte sind von der Prüfung ausgeschlossen. Der Titel lautet "[Numerische Berechnung]", es ist jedoch derzeit nicht geplant, eine Fortsetzung zu schreiben.

Frühere Forschungen:

Nach dem Artikel "Vergleich der Berechnungsgeschwindigkeiten in verschiedenen Sprachen" werde ich die Bewertung der Leibniz-Reihe aufnehmen. Ich weiß nicht, ob es so oft berechnet wird ... Außerdem wird WebAssembly mit der Geschwindigkeit des nativen Codes in Bezug auf die Geschwindigkeit verglichen, die der nativen Ausführung nahe kommt.

[04-22 19: 40] Ein Codefehler wurde behoben und gleichzeitig die Anzahl der Schleifen auf 1e9 erhöht.

Native Ausführung

Die Umgebung ist Debian 10.3 unter Win10 (WSL), Intel Core i7-6700 CPU bei 3,40 GHz.

C Sprache

Unter dem Gesichtspunkt des numerischen Berechnungsbenchmarks denke ich, dass die Geschwindigkeit der Muttersprache C immer noch der Standard ist, daher werde ich mit der Sprache C beginnen. Sie wird anhand des Codes des Originalartikels korrigiert.

leibniz.c


# include <stdio.h>
int main(void){
  int i;
  double sum = 0.0;
  int signum = 1;
  double denom = 1.0;
  
  for (i = 0; i<=1e9; i++) {
    sum += signum / denom;
    signum *= -1;
    denom += 2.0;
  };
  printf("Ans:%.16f\n", 4.0*sum);
  return 0;
}

Rust

leibniz.rs


fn main() {
    let mut sum: f64 = 0.0;
    let mut signum = 1;
    let mut denom = 1.0;

    for _ in 0..=1_000_000_000 {
        sum += signum as f64 / denom;
        signum *= -1;
        denom += 2.0;
    }
    println!("Ans:{:.16}", 4.*sum);
}

JS (Node.js)

leibniz.js


var sum = 0.0;
var signum = 1;
var denom = 1.0;

for (var i = 0; i<=1e9; i++) {
    sum += signum / denom;
    signum *= -1;
    denom += 2.0;
}
console.log('%d',4.0*sum);

Ergebnis

Dieser Wert ist das Ergebnis einer nur einmaligen Ausführung, wurde jedoch mehrmals wiederholt und es wurde bestätigt, dass der Fehler nur die letzte schwankende Ziffer war.

$ gcc --version
gcc (Debian 8.3.0-6) 8.3.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ gcc leibniz.c -o leibniz
$ time ./leibniz
real    0m2.596s
user    0m2.578s
sys     0m0.000s
$ gcc -O3 leibniz.c -o leibniz
$ time ./leibniz
Ans:3.1415926545880506

real    0m1.136s
user    0m1.125s
sys     0m0.016s
$ gcc -O3 -march=native leibniz.c -o leibniz
$ time ./leibniz
Ans:3.1415926545880506

real    0m1.133s
user    0m1.125s
sys     0m0.000s
$ rustc --version
rustc 1.42.0 (b8cedc004 2020-03-09)
$ rustc leibniz.rs
$ time ./leibniz
Ans:3.1415926545880506

real    0m36.107s
user    0m36.094s
sys     0m0.016s
$ rustc -C opt-level=3 leibniz.rs
$ time ./leibniz
Ans:3.1415926545880506

real    0m1.124s
user    0m1.094s
sys     0m0.031s
$ rustc -C opt-level=3 -C target-cpu=native leibniz.rs
$ time ./leibniz
Ans:3.1415926545880506

real    0m1.181s
user    0m1.156s
sys     0m0.031s
$ node --version
v12.16.2
$ time node leibniz.js
3.1415926545880506

real    0m1.989s
user    0m1.953s
sys     0m0.047s

~~ Selbst bei der Optimierung ist C unerwartet langsam ... Rost ist ungefähr viermal schneller, aber ich frage mich, ob ich einen Fehler gemacht habe. Rost ohne Optimierung war am langsamsten und Rost mit Optimierung war am schnellsten. . ~~

Nach der Optimierung waren sowohl die C-Sprache als auch Rust etwa 1,13 Sekunden lang. Der Knoten ist etwa 75% langsamer.

Im Browser ausführen

Ich habe derzeit kein Google Chrome, daher habe ich es nur mit Mozilla Firefox 75.0 unter Win10 versucht.

JS

Ich bin nicht an der Zeit des HTML-Renderings usw. interessiert. Klicken Sie also auf die Schaltfläche, um die Berechnung zu starten.

leibniz.html


<!DOCTYPE html>
<html>
  <head>
    <title>Leibniz Series</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
  </head>

  <body>
    <button id="start">Start!</button>
    
    <script>
      function leibniz() {
          var sum = 0.0;
          var signum = 1;
          var denom = 1.0;

          for (var i = 0; i<=1e9; i++) {
              sum += signum / denom;
              signum *= -1;
              denom += 2.0;
          }
          console.log('%f',4.0*sum);
      }

      let button = document.getElementById("start");
      button.addEventListener("click", () => {
          const startTime = performance.now()
          leibniz();
          const endTime = performance.now();
          console.log(endTime - startTime); 
      });
    </script>
  </body>
</html>

Das Ergebnis war ~~ 0.168 Sek. ~~ 1.660 Sek. Es ist nur ungefähr ~~ 30% ~~ 45% langsamer als die optimierte C-Sprache. Es ist beängstigend schnell ...

Rust (wasm)

src/lib.rs


use wasm_bindgen::prelude::*;

#[wasm_bindgen]
extern "C" {
    #[wasm_bindgen(js_namespace=console)]
    fn log(s: String);
}

#[wasm_bindgen]
pub fn leibniz() {
    let mut sum: f64 = 0.0;
    let mut signum = 1;
    let mut denom = 1.0;

    for _ in 0..=1_000_000_000 {
        sum += signum as f64 / denom;
        signum *= -1;
        denom += 2.0;
    }
    log(format!("Ans:{:.16}", 4.*sum));
}

index.html


<!DOCTYPE html>
<html>
  <head>
    <title>Leibniz Series</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
  </head>

  <body>
    <button id="start">Start!</button>

    <script type="module">
        import init, {leibniz} from '/pkg/rust_wasm.js';

        let button = document.getElementById("start");
        button.addEventListener("click", async () => {
            const startTime = performance.now()
            await init();
            leibniz();
            const endTime = performance.now();
            console.log(endTime - startTime); 
        });
    </script>
  </body>
</html>

Das Ergebnis war ~ ~ 0,035 Sek. ~ ~ 1,462 Sek. ~~ Es ist fast die gleiche Geschwindigkeit wie Rust nach der Optimierung (ungefähr 10% langsamer) ~~ Schneller als JS und ungefähr 30% langsamer als native.

Die Zeit zum Aufrufen der Initialisierungsfunktion "init ()" wird ebenfalls gemessen, aber selbst native Benutzer messen die Zeit vom Lesen der Binärdatei bis zum Ende der Verarbeitung, sodass die Messung so gleich wie möglich ist. Übrigens, als ich die Zeit nach dem Aufruf von "init" gemessen habe, waren es ungefähr ~ ~ 0,015 Sekunden ~ ~ 1,381 Sekunden.

Fazit

Es wurde bestätigt, dass WebAssembly in der reinen numerischen Berechnung selbst ungefähr 5-mal schneller als JS ist, und es ist ungefähr 15% schneller als native, aber nicht so schnell wie native. In diesem Artikel jedoch Da der Code nur vier Regeln für Ganzzahl- und Gleitkommazahlen enthält, kann sich das Ergebnis bei anderer Verarbeitung (z. B. Leistungsstärke), Funktionsaufruf und Speicherzugriff erneut ändern. In früheren Studien scheint es, dass wasm JS bisher nicht überzeugt hat. ~~

Was passiert übrigens, wenn Sie wasm in Node.js aufrufen? Ich dachte, ich würde es versuchen, aber ich bin erschöpft, also werde ich es wieder tun.

Recommended Posts

Ist WebAssembly wirklich schnell? [Numerische Berechnung]
Objektorientierte numerische Berechnung
Ist WebAssembly wirklich schnell? [Numerische Berechnung]
Ruby / Rust-Kooperation (3) Numerische Berechnung mit FFI
Ruby / Rust-Verknüpfung (4) Numerische Berechnung mit Rutie
Ruby / Rust-Kooperation (5) Numerische Berechnung mit Rutie ② Veggie
Objektorientierte numerische Berechnung
Ist die Kurzschlussauswertung wirklich schnell? Unterschied zwischen && und & in Java