"Si un ouvrier veut bien faire son travail, il doit d'abord affûter ses outils." - Confucius, "Les Entretiens de Confucius. Lu Linggong"
Page de garde > La programmation > La quête de la performance, partie II : Perl vs Python

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

Publié le 2024-08-01
Parcourir:312

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 les performances avec
quelques implémentations Python. Commençons par préparer la scène pour les calculs et fournissons la ligne de commande
capacités du 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 :

  • Python de base
  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 pu 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 devons 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



qui a donné le résultat de synchronisation 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
  • Le fait de 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.
Déclaration de sortie Cet article est reproduit sur : https://dev.to/chrisarg/the-quest-for-performance-part-ii-perl-vs-python-5gdg?1 En cas de violation, veuillez contacter [email protected] pour le supprimer
Dernier tutoriel Plus>

Clause de non-responsabilité: Toutes les ressources fournies proviennent en partie d'Internet. En cas de violation de vos droits d'auteur ou d'autres droits et intérêts, veuillez expliquer les raisons détaillées et fournir une preuve du droit d'auteur ou des droits et intérêts, puis l'envoyer à l'adresse e-mail : [email protected]. Nous nous en occuperons pour vous dans les plus brefs délais.

Copyright© 2022 湘ICP备2022001581号-3