Maison  >  Article  >  développement back-end  >  La quête de la performance, partie II : Perl vs Python

La quête de la performance, partie II : Perl vs Python

WBOY
WBOYoriginal
2024-07-31 12:37:22674parcourir

The Quest for Performance Part II : Perl vs Python


Après avoir exécuté un exemple de performance de jouet, nous allons maintenant m'éloigner quelque peu et comparer la performance avec
quelques implémentations Python. Commençons par préparer la scène pour les calculs et fournissons la ligne de commande
capacités au script Python.

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()

Et voici nos candidats :

  • BasePython
  for i in range(len(array0)):
    array0[i] = math.cos(math.sin(math.sqrt(array0[i])))
  • Numpy (un seul thread)
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 (notez que cet exemple n'est pas un véritable exemple sur place, mais je n'ai pas réussi à le faire fonctionner en utilisant les arguments out)
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)

Et voici les résultats du timing :

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

Le numba est étonnamment plus lent !? Cela pourrait-il être dû à la surcharge de compilation, comme l'a souligné mohawk2 dans un échange IRC sur ce problème ?
Pour tester cela, nous devrions appeler computing_inplace_with_numba une fois avant d'exécuter le benchmark. Cela montre que Numba est désormais plus rapide que Numpy.

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

Finalement, j'ai décidé de prendre la base R pour rouler dans le même exemple :

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))

ce qui a donné le résultat de timing suivant :

Time in base R: 1.30 seconds

Par rapport aux résultats Perl, nous notons ce qui suit à propos de cet exemple :

  • Les opérations sur place dans Python de base étaient ~ 3,5 plus lentes que Perl
  • PDL à thread unique et numpy ont donné des résultats presque identiques, suivis de près par la base R
  • Ne pas prendre en compte la surcharge de compilation de Numba donne la fausse impression qu'il est plus lent que Numpy. En tenant compte de la surcharge de compilation, Numba est x2 plus rapide que Numpy
  • La parallélisation avec Joblib s'est améliorée par rapport à Python de base, mais était toujours inférieure à l'implémentation Perl à thread unique
  • Le PDL multithread (et OpenMP) a écrasé (pas planté !) toutes les autres implémentations dans toutes les langues). J'espère que ce post donne matière à réflexion le langage à utiliser pour votre prochaine opération gourmande en données/calcul. La prochaine partie de cette série examinera le même exemple utilisant des tableaux en C. Ce dernier volet fournira (espérons-le) quelques informations sur l'impact de la localité mémoire et la surcharge induite par l'utilisation de langages typés dynamiquement.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn