Table des matières
Contenu de la question
Solution
Maison développement back-end Golang Pourquoi la lecture et l'écriture de fichiers en Go sont-elles beaucoup plus lentes qu'en Perl ?

Pourquoi la lecture et l'écriture de fichiers en Go sont-elles beaucoup plus lentes qu'en Perl ?

Feb 09, 2024 pm 09:30 PM
bibliothèque standard

为什么 Go 中读写文件比 Perl 慢很多?

Pourquoi la lecture et l'écriture de fichiers en Go sont-elles beaucoup plus lentes qu'en Perl ? Il s'agit d'un problème courant que de nombreux développeurs rencontrent lorsqu'ils utilisent ces deux langages de programmation. Dans cet article, l'éditeur PHP Strawberry répondra à cette question pour vous. Lorsque nous comparons la vitesse de lecture et d'écriture de fichiers entre Go et Perl, nous devons prendre en compte deux facteurs clés : les fonctionnalités du langage et l'implémentation sous-jacente. La philosophie de conception du langage Go en termes de lecture et d'écriture de fichiers est différente de celle de Perl, ce qui entraîne des différences de performances. Dans le même temps, la mise en œuvre sous-jacente est également un facteur important affectant la vitesse de lecture et d’écriture. Ensuite, nous analyserons ces facteurs en détail pour vous aider à mieux comprendre pourquoi la lecture et l'écriture de fichiers en Go sont beaucoup plus lentes qu'en Perl.

Contenu de la question

J'utilise go pour améliorer l'efficacité du code, mais lorsque j'utilise go pour lire et écrire des fichiers, je trouve que son efficacité en lecture et en écriture n'est pas aussi élevée que celle de Perl. Est-ce un problème avec mon code ou d'autres raisons ?

Construire le fichier d'entrée :

# input file:
for i in $(seq 1 600000) do     echo server$((random%800+100)),$random,$random,$random >> sample.csv done
Copier après la connexion

Lire et écrire des fichiers en utilisant Perl :

time cat sample.csv | perl -ne 'chomp;print"$_"' > out.txt
Copier après la connexion
real    0m0.249s
user    0m0.083s
sys 0m0.049s
Copier après la connexion

Utilisez go pour lire et écrire des fichiers :

package main

import (
    "bufio"
    "fmt"
    "io"
    "os"
    "strings"
)

func main() {

    filepath := "./sample.csv"
    file, err := os.openfile(filepath, os.o_rdwr, 0666)
    if err != nil {
        fmt.println("open file error!", err)
        return
    }
    defer file.close()
    buf := bufio.newreader(file)
    for {
        line, err := buf.readstring('\n')
        line = strings.trimspace(line)
        fmt.println(line)
        if err != nil {
            if err == io.eof {
                fmt.println("file read ok!")
                break
            } else {
                fmt.println("read file error!", err)
                return
            }
        }
    }
}
Copier après la connexion

Puis je cours :

time go run read.go > out.txt
Copier après la connexion
real    0m2.332s
user    0m0.326s
sys 0m2.038s
Copier après la connexion

Pourquoi la vitesse de lecture et d'écriture de Go est-elle près de 10 fois plus lente que celle de Perl ?

Solution

Vous comparez des pommes avec des oranges.

Il y a au moins deux erreurs de méthode :

  1. Votre mantra Perl mesure cat 如何读取文件并通过 pipe(2) 发送其内容,而 perl lit les données à partir de là, les traite et écrit les résultats sur sa sortie standard.

  2. Votre sort Go

    • Mesurez le processus de construction complet de la chaîne d'outils go (y compris la compilation, la liaison et l'écriture du fichier image exécutable) Puis exécutez composants d'un programme compilé, et
    • Mesure les écritures sans tampon sur la sortie standard (fmt.print* appels) lors de l'écriture sur la sortie standard à partir du code Perl - citant les docs - "Si la sortie est vers un terminal, la mise en mémoire tampon de ligne est généralement possible, sinon la mise en mémoire tampon de bloc est possible."
  3. Essayons de comparer des pommes avec des pommes.

Tout d’abord, voici une implémentation go similaire :

package main

import (
    "bufio"
    "bytes"
    "fmt"
    "os"
)

func main() {
    in := bufio.newscanner(os.stdin)
    out := bufio.newwriter(os.stdout)

    for in.scan() {
        s := bytes.trimspace(in.bytes())

        if _, err := out.write(s); err != nil {
            fmt.fprint(os.stderr, "failed to write file:", err)
            os.exit(1)
        }
    }

    if err := out.flush(); err != nil {
        fmt.fprint(os.stderr, "failed to write file:", err)
        os.exit(1)
    }

    if err := in.err(); err != nil {
        fmt.fprint(os.stderr, "reading failed:", err)
        os.exit(1)
    }
}
Copier après la connexion

Enregistrons-le sous

et mesurons-le :

chomp.go

    Code de construction :
  1. $ go build chomp.go

  2. Générer le fichier d'entrée :
  3. $ for i in $(seq 1 600000);执行 echo server$((random%800+100)),$random,$random,$random;完成 >sample.csv

  4. Exécuter le code Perl :
  5. $ time { perl -ne 'chomp; print "$_";' <sample.csv >out1.txt; }
    
    real    0m0.226s
    user    0m0.102s
    sys 0m0.048s
    Copier après la connexion

  6. Exécutez-le à nouveau pour vous assurer qu'il a lu le fichier d'entrée à partir du cache du système de fichiers :
  7. $ time { perl -ne 'chomp; print "$_";' <sample.csv >out1.txt; }
    
    real   0m0.123s
    user   0m0.090s
    sys    0m0.033s
    Copier après la connexion

    Remarquez comment le temps d'exécution est réduit.

  8. Exécutez le code Go sur l'entrée mise en cache :
  9. $ time { ./chomp <sample.csv >out2.txt; }
    
    real   0m0.063s
    user   0m0.032s
    sys    0m0.032s
    Copier après la connexion

    Assurez-vous que les résultats sont les mêmes :
  10. $ cmp out1.txt out2.txt

  11. Comme vous pouvez le voir, sur mon système avec un SSD, les résultats sont à peu près les mêmes.

    linux/amd64Eh bien, je dois également souligner que pour obtenir des résultats raisonnables, vous devrez exécuter chaque commande, disons 1 000 fois, faire la moyenne des résultats dans chaque lot, puis comparer les chiffres, mais je pense que cela suffit pour prouver ce que vous êtes. Le problème avec la méthode est.

    Encore une chose à considérer : le temps d'exécution de ces deux programmes est largement dominé par les E/S du système de fichiers, donc si vous pensez que cela sera plus rapide, vos attentes sont infondées : ces deux programmes sont volumineux Une partie du temps

    dormir

    dans le système du noyau appelle read(2) et write(2 ). Un programme go peut être plus rapide qu'un programme Perl dans certains cas impliquant des opérations CPU (surtout s'il est écrit pour tirer parti d'un système multicœur), mais ce n'est pas du tout le cas avec votre exemple. read(2)write(2) Oh, juste pour que ce soit clair : même si la spécification du langage go ne dit pas

    aot

    , et go run est un hack pour des concerts ponctuels et ponctuels, pas travail sérieux, il n’exécute pas non plus de code d’une complexité sérieuse. En bref, go-that-you-are-use n'est pas un langage interprété, bien que la disponibilité de go run puisse le faire paraître tel. En effet, il fait ce que go build normal ferait, puis exécute l'exécutable résultant, puis le supprime. go run 是一种针对一次性一次性演出的 hack,严肃的工作,也不执行任何严重复杂程度的代码。简而言之,go-that-you-are-using 并不是一种解释性语言,尽管 go run 的可用性可能使它看起来如此。事实上,它执行正常 go build

    Vous pourriez être tenté de dire que Perl gère également le "code source", mais l'interpréteur Perl est hautement optimisé pour la gestion des scripts et la chaîne d'outils de construction de Go - tout en étant incroyablement rapide par rapport à la plupart des autres langages compilés - n'est pas conçue pour cela. optimisé.
    La différence la plus évidente est peut-être que l'interpréteur Perl interprètevotre script (très simple), alors que chompprint 是所谓的“内置函数”,很容易提供给由解释器执行脚本。与构建 go 程序相比,编译器解析源代码文件并将其转换为机器代码,链接器实际上读取 go 标准库的编译包的文件 - 所有这些都是 imported, - 从它们,组合所有这些机器代码并写出一个可执行图像文件(这很像 perlle binaire lui-même ! ); bien sûr, il s’agit d’un processus très consommateur de ressources et n’a rien à voir avec l’exécution réelle du programme.

    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 de ce site Web
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

Outils d'IA chauds

Undresser.AI Undress

Undresser.AI Undress

Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover

AI Clothes Remover

Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool

Undress AI Tool

Images de déshabillage gratuites

Clothoff.io

Clothoff.io

Dissolvant de vêtements AI

AI Hentai Generator

AI Hentai Generator

Générez AI Hentai gratuitement.

Article chaud

R.E.P.O. Crystals d'énergie expliqués et ce qu'ils font (cristal jaune)
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Meilleurs paramètres graphiques
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Comment réparer l'audio si vous n'entendez personne
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25: Comment déverrouiller tout dans Myrise
3 Il y a quelques semaines By 尊渡假赌尊渡假赌尊渡假赌

Outils chauds

Bloc-notes++7.3.1

Bloc-notes++7.3.1

Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Comment utiliser la valeur absolue en C++ Comment utiliser la valeur absolue en C++ May 06, 2024 pm 06:15 PM

Il existe deux manières d'obtenir des valeurs absolues en C++ : 1. Utilisez la fonction intégrée abs() pour obtenir la valeur absolue d'un type entier ou à virgule flottante 2. Utilisez la fonction générique std::abs() pour ; obtenir diverses valeurs absolues prises en charge. Fonctionne sur les valeurs absolues des types de données.

Comment utiliser std :: en C++ Comment utiliser std :: en C++ May 09, 2024 am 03:45 AM

std est l'espace de noms en C++ qui contient les composants de la bibliothèque standard. Pour utiliser std, utilisez l'instruction "using namespace std;". L'utilisation de symboles directement à partir de l'espace de noms std peut simplifier votre code, mais n'est recommandée que lorsque cela est nécessaire pour éviter la pollution de l'espace de noms.

Comment faire apparaître une fenêtre en python Comment faire apparaître une fenêtre en python May 05, 2024 pm 08:15 PM

Il existe deux manières de créer des popups en Python : Tkinter : utilisez la bibliothèque Tkinter pour créer des widgets Tk ou TopLevel. Pyglet : utilisez la bibliothèque Pyglet pour créer des fenêtres Window.

Que signifie fabs en C++ Que signifie fabs en C++ May 08, 2024 am 01:15 AM

La fonction fabs() est une fonction mathématique en C++ qui calcule la valeur absolue d'un nombre à virgule flottante, supprime le signe négatif et renvoie une valeur positive. Il accepte un paramètre à virgule flottante et renvoie une valeur absolue de type double. Par exemple, fabs(-5.5) renvoie 5,5. Cette fonction fonctionne avec des nombres à virgule flottante, dont la précision est affectée par le matériel sous-jacent.

Que signifie premier en C++ Que signifie premier en C++ May 07, 2024 pm 11:33 PM

prime est un mot-clé en C++, indiquant le type de nombre premier, qui ne peut être divisé que par 1 et lui-même. Il est utilisé comme type booléen pour indiquer si la valeur donnée est un nombre premier. S'il s'agit d'un nombre premier, c'est le cas. vrai, sinon c'est faux.

Que signifie la configuration en Java ? Que signifie la configuration en Java ? May 07, 2024 am 02:39 AM

Config représente les informations de configuration en Java et est utilisé pour ajuster le comportement de l'application. Il est généralement stocké dans des fichiers ou des bases de données externes et peut être géré via Java Properties, PropertyResourceBundle, Java Configuration Framework ou des bibliothèques tierces. Ses avantages incluent le découplage et la flexibilité. sensibilisation à l'environnement, gérabilité, évolutivité.

_utilisation complexe en langage C _utilisation complexe en langage C May 08, 2024 pm 01:27 PM

Le type complexe est utilisé pour représenter des nombres complexes en langage C, y compris des parties réelles et imaginaires. Sa forme d'initialisation est complex_number = 3.14 + 2.71i, la partie réelle est accessible via creal(complex_number) et la partie imaginaire est accessible via cimag(complex_number). Ce type prend en charge les opérations mathématiques courantes telles que l'addition, la soustraction, la multiplication, la division et le modulo. De plus, un ensemble de fonctions permettant de travailler avec des nombres complexes est fourni, telles que cpow, csqrt, cexp et csin.

Que signifie min en C++ Que signifie min en C++ May 08, 2024 am 12:51 AM

La fonction min en C++ renvoie le minimum de plusieurs valeurs. La syntaxe est : min(a, b), où a et b sont les valeurs à comparer. Vous pouvez également spécifier une fonction de comparaison pour prendre en charge les types qui ne prennent pas en charge l'opérateur <. C++20 a introduit la fonction std::clamp, qui gère le minimum de trois valeurs ou plus.

See all articles