Heim  >  Artikel  >  Backend-Entwicklung  >  Das Streben nach Leistung Teil II: Perl vs. Python

Das Streben nach Leistung Teil II: Perl vs. Python

WBOY
WBOYOriginal
2024-07-31 12:37:22674Durchsuche

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

Der Numba ist überraschend langsamer!? Könnte es am 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 im selben Beispiel entschieden:

n<-50000000
x<-runif(n)
start_time <- Sys.time()
result <- cos(sin(sqrt(x)))
end_time <- Sys.time()

# Calculate the time taken
time_taken <- end_time - start_time

# Print the time taken
print(sprintf("Time in base R: %.2f seconds", time_taken))

was zu folgendem Timing-Ergebnis führte:

Time in base R: 1.30 seconds

Im Vergleich zu den Perl-Ergebnissen stellen wir Folgendes zu diesem Beispiel fest:

  • Inplace-Operationen in Basis-Python waren ca. 3,5 langsamer als Perl
  • Single-Threaded-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 hat zwar eine Verbesserung gegenüber Basis-Python erzielt, 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.

Das obige ist der detaillierte Inhalt vonDas Streben nach Leistung Teil II: Perl vs. Python. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn