"Se um trabalhador quiser fazer bem o seu trabalho, ele deve primeiro afiar suas ferramentas." - Confúcio, "Os Analectos de Confúcio. Lu Linggong"
Primeira página > Programação > A busca pelo desempenho, parte II: Perl vs Python

A busca pelo desempenho, parte II: Perl vs Python

Publicado em 01/08/2024
Navegar:440

The Quest for Performance Part II : Perl vs Python


Tendo apresentado um exemplo de desempenho de brinquedo, agora faremos uma pequena digressão e compararemos o desempenho com
algumas implementações Python. Primeiro vamos preparar o cenário para os cálculos e fornecer a linha de comando
recursos para o 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()

E aqui estão nossos concorrentes:

  • Python básico
  for i in range(len(array0)):
    array0[i] = math.cos(math.sin(math.sqrt(array0[i])))
  • Numpy (thread único)
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 (observe que este exemplo não é verdadeiro no local, mas não consegui executá-lo usando os argumentos 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)

E aqui estão os resultados do tempo:

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

O numba é surpreendentemente mais lento!? Poderia ser devido à sobrecarga de compilação, conforme apontado por mohawk2 em uma troca de IRC sobre esse assunto?
Para testar isso, devemos chamar computate_inplace_with_numba uma vez antes de executarmos o benchmark. Fazer isso mostra que Numba agora é mais rápido 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

Finalmente, decidi usar a base R para passeio no mesmo exemplo:

n



que produziu o seguinte resultado de tempo:

Time in base R: 1.30 seconds

Em comparação com os resultados Perl, observamos o seguinte sobre este exemplo:

  • As operações Inplace no Python base eram ~ 3,5 mais lentas do que Perl
  • PDL de thread único e numpy forneceram resultados quase idênticos, seguidos de perto pelo R básico
  • A falha em levar em conta a sobrecarga de compilação do Numba produz a falsa impressão de que ele é mais lento que o Numpy. Ao contabilizar a sobrecarga de compilação, Numba é x2 mais rápido que Numpy
  • A paralelização com Joblib melhorou em relação ao Python básico, mas ainda era inferior à implementação Perl de thread único
  • PDL multithread (e OpenMP) esmagou (não travou!) todas as outras implementações em todos os idiomas). Espero que esta postagem fornece algum alimento para reflexão o idioma a ser usado em sua próxima operação intensiva de dados/computação. A próxima parte desta série examinará o mesmo exemplo usando arrays em C. Esta parte final irá (esperançosamente) fornecer alguns insights sobre o impacto da localidade da memória e a sobrecarga incorrida pelo uso de linguagens de tipo dinâmico.
Declaração de lançamento Este artigo foi reproduzido em: https://dev.to/chrisarg/the-quest-for-performance-part-ii-perl-vs-python-5gdg?1 Se houver alguma violação, entre em contato com [email protected] para excluí-lo
Tutorial mais recente Mais>

Isenção de responsabilidade: Todos os recursos fornecidos são parcialmente provenientes da Internet. Se houver qualquer violação de seus direitos autorais ou outros direitos e interesses, explique os motivos detalhados e forneça prova de direitos autorais ou direitos e interesses e envie-a para o e-mail: [email protected]. Nós cuidaremos disso para você o mais rápido possível.

Copyright© 2022 湘ICP备2022001581号-3