Heim  >  Artikel  >  Backend-Entwicklung  >  Benchmarking der CSV-Dateiverarbeitung: Golang vs. NestJS vs. PHP vs. Python

Benchmarking der CSV-Dateiverarbeitung: Golang vs. NestJS vs. PHP vs. Python

WBOY
WBOYOriginal
2024-08-12 22:34:02982Durchsuche

Einführung

Die effiziente Verarbeitung großer CSV-Dateien ist eine häufige Anforderung in vielen Anwendungen, von der Datenanalyse bis hin zu ETL-Prozessen (Extrahieren, Transformieren, Laden). In diesem Artikel möchte ich die Leistung von vier beliebten Programmiersprachen – Golang, NodeJS mit NestJS, PHP und Python – bei der Verarbeitung großer CSV-Dateien auf einem MacBook Pro M1 vergleichen. Mein Ziel ist es herauszufinden, welche Sprache die beste Leistung für diese Aufgabe bietet.

Testumgebung

Hardware: MacBook Pro M1, 256 GB SSD, 8 GB RAM

Software:

  • macOS Sonoma 14.5
  • PHP 8.3.6
  • Golang 1.22.4
  • Node.js 22.0.0 mit NestJS
  • Python 3.12.3

Testdaten

Ich habe eine synthetische CSV-Datei namens sales_data.csv mit etwa 1 Million Zeilen verwendet, von denen jede Transaktionsdetails wie Transaktions-ID, Produkt-ID, Menge, Preis und Zeitstempel enthält.

Aufgabenbeschreibung

Für jede Sprache führt das Skript die folgenden Aufgaben aus:

  1. Liest die CSV-Datei.
  2. Berechnet den Gesamtverkaufsbetrag.
  3. Identifiziert das Produkt mit den höchsten Umsätzen.

Durchführung

Hier sind die Skripte, die für jede Sprache verwendet werden:

Golang-Skript:

sales.go

package main

import (
    "encoding/csv"
    "fmt"
    "os"
    "strconv"
    "time"
)

func main() {
    start := time.Now()

    file, err := os.Open("../generate-csv/sales_data.csv")
    if err != nil {
        fmt.Println("Error:", err)
        return
    }
    defer file.Close()

    reader := csv.NewReader(file)
    _, _ = reader.Read() // Skip header

    totalSales := 0.0
    productSales := make(map[string]float64)

    for {
        line, err := reader.Read()
        if err != nil {
            break
        }
        productID := line[1]
        quantity, _ := strconv.Atoi(line[2])
        price, _ := strconv.ParseFloat(line[3], 64)
        total := float64(quantity) * price

        totalSales += total
        productSales[productID] += total
    }

    var topProduct string
    var topSales float64
    for product, sales := range productSales {
        if sales > topSales {
            topProduct = product
            topSales = sales
        }
    }

    elapsed := time.Since(start)
    fmt.Printf("Golang Execution time: %s\n", elapsed)
    fmt.Printf("Total Sales: $%.2f\n", totalSales)
    fmt.Printf("Top Product: %s with sales $%.2f\n", topProduct, topSales)
}

NestJS-Skript:

csv.service.ts

import { Injectable } from '@nestjs/common';
import * as fs from 'fs';
import * as fastcsv from 'fast-csv';

// path file CSV
const GLOBAL_CSV_PATH = '../generate-csv/sales_data.csv';

@Injectable()
@Injectable()
export class CsvService {
  async parseCsv(): Promise<{
    nestExecutionTime: number;
    totalSales: number;
    topProductSales: number;
  }> {
    return new Promise((resolve, reject) => {
      const startTime = process.hrtime();

      let totalSales = 0;
      const productSales: { [key: string]: number } = {};

      fs.createReadStream(GLOBAL_CSV_PATH)
        .pipe(fastcsv.parse({ headers: true, delimiter: ',' }))
        .on('data', (row) => {
          const productID = row.product_id;
          const quantity = parseInt(row.quantity, 10);
          const price = parseFloat(row.price);
          const total = quantity * price;
          totalSales += total;
          if (!productSales[productID]) {
            productSales[productID] = 0;
          }
          productSales[productID] += total;
        })
        .on('end', () => {
          const topProduct = Object.keys(productSales).reduce((a, b) =>
            productSales[a] > productSales[b] ? a : b,
          );
          const topProductSales = productSales[topProduct] || 0;
          const endTime = process.hrtime(startTime);
          const nestExecutionTime = endTime[0] + endTime[1] / 1e9;

          console.log(`NestJS Execution time: ${nestExecutionTime} seconds`);
          console.log(`Total Sales: $${totalSales}`);
          console.log(
            `Top Product: ${topProduct} with sales $${topProductSales}`,
          );

          resolve({
            nestExecutionTime,
            totalSales,
            topProductSales,
          });
        })
        .on('error', (error) => reject(error));
    });
  }
}

csv.controller.ts

import { Controller, Get } from '@nestjs/common';
import { CsvService } from './csv.service';

@Controller('csv')
export class CsvController {
  constructor(private readonly csvService: CsvService) {}

  @Get('parse')
  async parseCsv(): Promise<{
    nestExecutionTime: number;
    totalSales: number;
    topProductSales: number;
  }> {
    return this.csvService.parseCsv();
  }
}

PHP-Skript

sales.php

<?php
$start_time = microtime(true);

$file = fopen("../generate-csv/sales_data.csv", "r");
$total_sales = 0;
$product_sales = [];

fgetcsv($file); // Skip header
while (($line = fgetcsv($file)) !== false) {
    $product_id = $line[1];
    $quantity = (int)$line[2];
    $price = (float)$line[3];
    $total = $quantity * $price;

    $total_sales += $total;
    if (!isset($product_sales[$product_id])) {
        $product_sales[$product_id] = 0;
    }
    $product_sales[$product_id] += $total;
}
fclose($file);

arsort($product_sales);
$top_product = array_key_first($product_sales);

$end_time = microtime(true);
$execution_time = ($end_time - $start_time);

echo "PHP Execution time: ".$execution_time." seconds\n";
echo "Total Sales: $".$total_sales."\n";
echo "Top Product: ".$top_product." with sales $".$product_sales[$top_product]."\n";

Python-Skript

import csv
import time

# Input file name config
input_file = '../generate-csv/sales_data.csv'


def parse_csv(file_path):
    start_time = time.time()

    total_sales = 0
    product_sales = {}

    with open(file_path, mode='r') as file:
        reader = csv.DictReader(file)

        for row in reader:
            product_id = row['product_id']
            quantity = int(row['quantity'])
            price = float(row['price'])
            total = quantity * price
            total_sales += total

            if product_id not in product_sales:
                product_sales[product_id] = 0
            product_sales[product_id] += total

    top_product = max(product_sales, key=product_sales.get)
    execution_time = time.time() - start_time

    return {
        'total_sales': total_sales,
        'top_product': top_product,
        'top_product_sales': product_sales[top_product],
        'execution_time': execution_time,
    }


if __name__ == "__main__":
    result = parse_csv(input_file)
    print(f"Python Execution time: {result['execution_time']:.2f} seconds")
    print(f"Total Sales: ${result['total_sales']:.2f}")
    print(f"Top Product: {result['top_product']} with sales ${
          result['top_product_sales']:.2f}")

Ergebnisse

Hier sind die Ergebnisse unserer Benchmark-Tests:

Golang

  • Ausführungszeit: 466,69975 ms
  • Gesamtumsatz: 274654985,36 ​​$
  • Top-Produkt: Produkt 1126 mit einem Umsatz von 305922,81 $

Benchmarking CSV File Processing: Golang vs NestJS vs PHP vs Python

NestJS

  • Ausführungszeit: 6,730134208 Sekunden
  • Gesamtumsatz: 274654985,36000216 $
  • Top-Produkt: 1126 mit einem Umsatz von 305922,8099999997 $

Benchmarking CSV File Processing: Golang vs NestJS vs PHP vs Python

PHP

  • Ausführungszeit: 1,5142710208893 Sekunden
  • Gesamtumsatz: 274654985,36 ​​$
  • Top-Produkt: 1126 mit einem Umsatz von 305922,81 $

Benchmarking CSV File Processing: Golang vs NestJS vs PHP vs Python

Python

  • Ausführungszeit: 2,56 Sekunden
  • Gesamtumsatz: 274654985,36 ​​$
  • Top-Produkt: 1126 mit einem Umsatz von 305922,81 $

Benchmarking CSV File Processing: Golang vs NestJS vs PHP vs Python

Analyse

Mein Benchmark bringt einige interessante Erkenntnisse zu Tage:

Ausführungszeit: Golang schnitt hinsichtlich der Ausführungszeit am besten ab, dicht gefolgt von PHP8, während NestJS die längste Zeit für die Erledigung der Aufgabe benötigte.
Speichernutzung: Build NestJS zeigte eine effiziente Speichernutzung, während Python einen höheren Speicherverbrauch zeigte.
Einfache Implementierung: Golang bot die einfachste Implementierung, während NestJS mehr Codezeilen und Komplexität erforderte.

Abschluss

Meinen Erkenntnissen zufolge bietet Golang die beste Leistungsgeschwindigkeit und Speichereffizienz, was es zu einer hervorragenden Wahl für die Verarbeitung großer Datenmengen macht.

Vollständiger Code

Den vollständigen Code finden Sie im My Github-Repository
csv-parsing-battle.

Das obige ist der detaillierte Inhalt vonBenchmarking der CSV-Dateiverarbeitung: Golang vs. NestJS vs. PHP 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