„Wenn ein Arbeiter seine Arbeit gut machen will, muss er zuerst seine Werkzeuge schärfen.“ – Konfuzius, „Die Gespräche des Konfuzius. Lu Linggong“
Titelseite > Programmierung > Das Streben nach Leistung Teil II: Perl vs. Python

Das Streben nach Leistung Teil II: Perl vs. Python

Veröffentlicht am 01.08.2024
Durchsuche:705

The Quest for Performance Part II : Perl vs Python


Nachdem wir ein Beispiel für die Leistung eines Spielzeugs durchgespielt haben, schweifen wir nun etwas ab und vergleichen die Leistung mit
ein paar Python-Implementierungen. Zuerst richten wir die Bühne für die Berechnungen ein und stellen die Befehlszeile
bereit. Funktionen des Python-Skripts.

import argparse
import time
import math
import numpy as np
import os
from numba import njit
from joblib import Parallel, delayed

parser = argparse.ArgumentParser()
parser.add_argument("--workers", type=int, default=8)
parser.add_argument("--arraysize", type=int, default=100_000_000)
args = parser.parse_args()
# Set the number of threads to 1 for different libraries
print("=" * 80)
print(
    f"\nStarting the benchmark for {args.arraysize} elements "
    f"using {args.workers} threads/workers\n"
)

# Generate the data structures for the benchmark
array0 = [np.random.rand() for _ in range(args.arraysize)]
array1 = array0.copy()
array2 = array0.copy()
array_in_np = np.array(array1)
array_in_np_copy = array_in_np.copy()

Und hier sind unsere Teilnehmer:

  • Basis-Python
  for i in range(len(array0)):
    array0[i] = math.cos(math.sin(math.sqrt(array0[i])))
  • Numpy (Single-Threaded)
np.sqrt(array_in_np, out=array_in_np)
np.sin(array_in_np, out=array_in_np)
np.cos(array_in_np, out=array_in_np)
  • Joblib (beachten Sie, dass es sich bei diesem Beispiel nicht um ein echtes In-Place-Beispiel handelt, ich es jedoch nicht mit den Out-Argumenten zum Laufen bringen konnte)
def compute_inplace_with_joblib(chunk):
    return np.cos(np.sin(np.sqrt(chunk))) #parallel function for joblib

chunks = np.array_split(array1, args.workers)  # Split the array into chunks
numresults = Parallel(n_jobs=args.workers)(
        delayed(compute_inplace_with_joblib)(chunk) for chunk in chunks
    )# Process each chunk in a separate thread
array1 = np.concatenate(numresults)  # Concatenate the results
  • Numba
@njit
def compute_inplace_with_numba(array):
    np.sqrt(array,array)
    np.sin(array,array)
    np.cos(array,array)
    ## njit will compile this function to machine code
compute_inplace_with_numba(array_in_np_copy)

Und hier sind die Timing-Ergebnisse:

In place in (  base Python): 11.42 seconds
In place in (Python Joblib): 4.59 seconds
In place in ( Python Numba): 2.62 seconds
In place in ( Python Numpy): 0.92 seconds

Die Numba ist überraschend langsamer!? Könnte es an dem Mehraufwand der Kompilierung liegen, wie mohawk2 in einem IRC-Austausch zu diesem Problem betonte?
Um dies zu testen, sollten wir einmal „compute_inplace_with_numba“ aufrufen, bevor wir den Benchmark ausführen. Dies zeigt, dass Numba jetzt schneller als Numpy ist.

In place in (  base Python): 11.89 seconds
In place in (Python Joblib): 4.42 seconds
In place in ( Python Numpy): 0.93 seconds
In place in ( Python Numba): 0.49 seconds

Schließlich habe ich mich für die Basis R für die Fahrt im selben Beispiel entschieden:

n



was zu folgendem Timing-Ergebnis führte:

Time in base R: 1.30 seconds

Im Vergleich zu den Perl-Ergebnissen fällt uns zu diesem Beispiel Folgendes auf:

  • Inplace-Operationen in Basis-Python waren ~ 3,5 langsamer als Perl
  • Einzelthread-PDL und Numpy lieferten nahezu identische Ergebnisse, dicht gefolgt von Basis-R
  • Wenn der Kompilierungsaufwand von Numba nicht berücksichtigt wird, entsteht der falsche Eindruck, dass es langsamer als Numpy ist. Unter Berücksichtigung des Kompilierungsaufwands ist Numba x2 schneller als Numpy
  • Die Parallelisierung mit Joblib verbesserte zwar die Basis-Python-Version, war aber immer noch schlechter als die Single-Thread-Perl-Implementierung
  • Multithreaded PDL (und OpenMP) hat jede andere Implementierung in allen Sprachen zerstört (nicht abgestürzt!). Hoffentlich dieser Beitrag gibt einige Denkanstöße die Sprache, die Sie für Ihren nächsten daten-/rechenintensiven Vorgang verwenden sollten. Der nächste Teil dieser Serie befasst sich mit demselben Beispiel unter Verwendung von Arrays in C. Dieser letzte Teil wird (hoffentlich) einige Erkenntnisse über die Auswirkungen der Speicherlokalität und den Overhead liefern, der durch die Verwendung dynamisch typisierter Sprachen entsteht.
Freigabeerklärung Dieser Artikel ist abgedruckt unter: https://dev.to/chrisarg/the-quest-for-performance-part-ii-perl-vs-python-5gdg?1 Bei Verstößen wenden Sie sich bitte an [email protected] um es zu löschen
Neuestes Tutorial Mehr>

Haftungsausschluss: Alle bereitgestellten Ressourcen stammen teilweise aus dem Internet. Wenn eine Verletzung Ihres Urheberrechts oder anderer Rechte und Interessen vorliegt, erläutern Sie bitte die detaillierten Gründe und legen Sie einen Nachweis des Urheberrechts oder Ihrer Rechte und Interessen vor und senden Sie ihn dann an die E-Mail-Adresse: [email protected] Wir werden die Angelegenheit so schnell wie möglich für Sie erledigen.

Copyright© 2022 湘ICP备2022001581号-3