[Go language] Essayez de créer un compteur de lignes inutilement multithread

introduction

Je ne peux pas me débarrasser de l'habitude de produire des choses inutiles. Cette fois, j'ai écrit un article sur le code du compteur de lignes qui était inutilement multithread.

Certains fichiers sont plus rapides que wc -l, ce qui peut être utile pour ceux qui souhaitent compter les lignes le plus rapidement.

Go étudie seul. Nous attendons avec impatience vos suggestions concernant les erreurs et une meilleure rédaction.

Livre de référence

"Traitement parallèle en langue Go" (Pourquoi ne l'avez-vous pas lu plus tôt?) Rubbing io.Reader (Parlez-moi de la cachette de Go?)

Fonctions à mettre en œuvre

Compte le nombre de lignes dans le fichier spécifié par l'argument et l'affiche à l'écran.

Les valeurs suivantes peuvent être spécifiées dans l'argument -Nom de fichier (-f) -Nombre de divisions pour la lecture fractionnée (-s) -Nombre de threads pour le traitement parallèle (-t) -Taille du tampon de lecture (-b)

Fonctionnalité

-Compte du nombre de lignes par traitement multi-thread en utilisant goroutine et canaux -Rubbing du fichier avec io.Reader (Rubbing io.Reader)

Flux de processus

Le flux de traitement général est le suivant.

  1. Recevez les informations d'option déjà mentionnées à partir de l'argument de ligne de commande
  2. Obtenez la taille du fichier (nombre d'octets) du fichier cible
  3. Divisez la taille du fichier par le nombre de divisions pour déterminer la position de début de lecture et la taille de lecture dont chaque processus est responsable.
  4. Démarrez goroutine pour le nombre spécifié de threads et comptez le nombre de lignes à partir de la position de début de lecture.
  5. Collectez le résultat du comptage de chaque goroutine via le canal et affichez le nombre total de lignes sur la console lorsque tout le traitement est terminé.

Dépôt

Le code complet est ici

Description du code

mettre la table

Importez les bibliothèques requises. Utilisez flag pour recevoir des arguments et glog pour la journalisation.

package main
    
import (
    "bytes"                            
    "flag"          
    "fmt"
    "io"
    "math"
    "os"
    "sync"
    "time"
            
    "github.com/golang/glog"
)

Déclarez des variables en définissant une structure pour recevoir des arguments.

// Arg is struct for commandline arg.
type Arg struct {          
    //Dossier à traiter
    targetFile string
        
    //Nombre de divisions lors du comptage des divisions
    splitNum int
        
    //Threads s'exécutant simultanément(Maximum)nombre
    maxThreads int
  
    //Taille du tampon pour la lecture des fichiers
    buffersize int
}                                                                     
                                                                         
var (
    arg Arg
)

Écrivez le processus d'expansion des arguments, etc.

Puisque glog prend son propre argument, nous utilisons flag pour redéfinir et initialiser le propre argument de glog. Lorsque la commande help est affichée, l'explication de l'argument de glog est également affichée et c'est déroutant, donc j'ai mis "(go-lc)" dans l'explication de l'argument de ce processus pour le distinguer (cette zone est plus intelligente) Il semble y avoir un moyen de l'écrire).

func init() {
    //Définir le message d'aide
    flag.Usage = func() {  
        fmt.Fprintf(os.Stderr, "%s\n", fmt.Sprintf("%s -f TARGETFILE [options] [glog options]", 
os.Args[0]))
        flag.PrintDefaults()
    }               
 
    //Réglage initial de l'enregistreur
    _ = flag.Set("stderrthreshold", "INFO")
    _ = flag.Set("v", "0")
        
    //Définition des options de ligne de commande
    flag.StringVar(&arg.targetFile, "f", "", "(go-lc) Target File.")
    flag.IntVar(&arg.splitNum, "s", 2, "(go-lc) Num of File split.")
    flag.IntVar(&arg.maxThreads, "t", 2, "(go-lc) Max Num of Threads.")
    flag.IntVar(&arg.buffersize, "b", 1024*1024, "(go-lc) Size of ReadBuffer(default=1024*1024).")
}

L'aide à la commande dans cette configuration s'affiche comme suit: L'aide de glog est assez bruyante.

(C'est bruyant, mais c'est facile pour un petit outil car vous n'avez pas à implémenter vous-même le processus de changement de niveau de journal.)

> ./bin/go-lc --help
./bin/go-lc -f TARGETFILE [options] [glog options]
  -alsologtostderr
        log to standard error as well as files
  -b int
        (go-lc) Size of ReadBuffer (default 1048576)
  -f string
        (go-lc) Target File
  -log_backtrace_at value
        when logging hits line file:N, emit a stack trace
  -log_dir string
        If non-empty, write log files in this directory
  -logtostderr
        log to standard error instead of files
  -s int
        (go-lc) Num of File split (default 2)
  -stderrthreshold value
        logs at or above this threshold go to stderr
  -t int
        (go-lc) Max Num of Threads (default 2)
  -v value
        log level for V logs
  -vmodule value
        comma-separated list of pattern=N settings for file-filtered logging

Traitement principal

Je vais d'abord expliquer le processus principal. Cependant, il appelle simplement la fonction getNumOfLines qui agrège, reçoit le résultat et l'affiche à l'écran.

func main() {
    flag.Parse()
            
    glog.V(1).Infof("Start")
            
    //Démarrer la minuterie pour le calcul du temps de traitement
    startTime := time.Now() 

    //Exécuter le traitement d'agrégation
    numOfLines, _ := getNumOfLines(arg.targetFile, arg.splitNum, arg.maxThreads, arg.buffersize)
            
    //Afficher le temps de traitement
    glog.V(1).Infof("End(%s)", time.Since(startTime))
            
    fmt.Printf("%d\n", numOfLines)
}

getFileSize()

Une fonction pour obtenir la taille du fichier. Voir les commentaires pour le traitement.

func getFileSize(filename string) (int, error) {
    //Ouvrez le fichier cible
    fh, err := os.OpenFile(filename, 0, 0)
    if err != nil {  
        return 0, err
    }
    defer fh.Close()

    //Obtenir des informations sur les fichiers
    fileinfo, err := fh.Stat()
    if err != nil {
        return 0, err
    }

    //Obtient et retourne le nombre d'octets dans le fichier
    return int(fileinfo.Size()), nil
}

getNumOfLines()

C'est getNumOfLines () que je lisais dans main. C'est une fonction un peu longue, donc je vais l'expliquer séparément.

La première partie calcule le nombre de lectures de tampon effectuées pour l'ensemble du fichier. La formule suivante.

*** Nombre de lectures = Taille du fichier / Taille du tampon (+1 si non divisible) ***

func getNumOfLines(filename string, splitNum int, maxThreads int, buffersize int) (int, error) {
    //Obtenir la taille du fichier
    fsize, err := getFileSize(filename)
    if err != nil {  
        return 0, err
    }

    // loglevel =Affichage d'informations avec 1
    glog.V(1).Infof("FileSize   : %10d byte", fsize)
    glog.V(1).Infof("Read buffer: %10d byte", buffersize)
    glog.V(1).Infof("Max Threads: %d", maxThreads)
    glog.V(1).Infof("Split Num  : %d", splitNum)

    //Calculez combien de fois il peut être lu en unités de taille de la mémoire tampon.
    var readCountTotal int = int(math.Trunc(float64(fsize) / float64(buffersize)))

    //S'il y a un reste, ajoutez 1 au nombre de lectures
    if fsize-(readCountTotal*buffersize) > 0 {
        readCountTotal++
    }

Ensuite, nous allons configurer le multi-threading. Waitgroup peut ne pas être nécessaire si vous déterminez comment utiliser le canal, mais il est utilisé par souci de clarté.

    //Initialiser le groupe d'attente de fin
    wg := &sync.WaitGroup{}

    //Canal pour limiter le nombre de courses simultanées de goroutine
    jc := make(chan interface{}, maxThreads)
    defer close(jc)

    //Canal pour recevoir le résultat du nombre de lignes de chaque goroutine
    counterCh := make(chan int, maxThreads)

    //A partir de la fin de veille goroutine de chaque goroutine,
    //Canal de renvoi des résultats agrégés au traitement principal
    resultCh := make(chan int)
    defer close(resultCh)

    //Démarrer la goroutine pour recevoir les résultats
    //La condition finale est proche(counterCh)
    go func(counterCh <-chan int) {
        cAll := 0
        for c := range counterCh {
            cAll += c

            glog.V(2).Infof("[receiver] receive: %d\n", c)
        }
     
        resultCh <- cAll
    }(counterCh)

Il s'agit d'une boucle qui démarre goroutine (countWorker) qui compte le nombre de lignes. byteOffset est la position de début de lecture. EachReadCount est le nombre de fois où le tampon a été lu, mais la méthode de calcul provient du site suivant. Diviser n entiers aussi uniformément que possible Certaines personnes sont intelligentes.

Un canal appelé jc permet de contrôler le nombre de démarrages simultanés. C'est une utilisation standard, mais je pense que l'URL suivante sera utile. Comment contrôler le nombre maximum de Goroutines Limiter le nombre de processus parallèles en fonction du nombre de processeurs en langage Go Au fait, les deux sites ci-dessus utilisent le type booléen et le type int, mais selon "Traitement parallèle par langage Go (O'Reilly)", "Une interface d'une capacité de 0 est bonne pour le canal pour contrôler le nombre de startups!" C'est.

    //Comptage de lignes Position de départ pour passer à la goroutine(0 est#Pour une goroutine)        
    var byteOffset int64 = 0

    //Boucle de comptage de lignes pour démarrer la goroutine
    for i := 0; i < splitNum; i++ {
        //Combien de fois lire le tampon dans countLinesInThread
        eachReadCount := int(math.Trunc(float64(readCountTotal+i) / float64(splitNum)))

        //Remplissez un tableau de numéros de démarrage de goroutine
        jc <- true

        //Augmenter le groupe d'attente de un
        wg.Add(1)

        //Ligne de départ comptage goroutine
        go countWorker(filename, eachReadCount, byteOffset, buffersize, wg, jc, counterCh)

        //Décalage de lecture avancé
        byteOffset += int64(eachReadCount * buffersize)
    }

    wg.Wait()
    close(counterCh)

    return <-resultCh, nil
}

countWorker()

Ensuite, définissez countWorker (), qui est le corps principal de goroutine. En fait, je viens d'ouvrir le fichier donné par filename, décale la position de lecture avec f.Seek, puis lis getNumOfCharsOnIo. Je pense que la partie qui ouvre le même fichier plusieurs fois est un peu redondante, mais comme il existe un processus de recherche pour la lecture fractionnée, je le fais (est-ce que cela a du sens de se séparer ici? J'ai un sentiment, mais je m'en fiche Dans certains cas, il est important d'avoir les premières intentions sur le site de développement des adultes).

func countWorker(filename string, eachReadCount int, byteOffset int64, buffersize int,
    wg *sync.WaitGroup, jc <-chan interface{}, counter chan<- int) {
    var c int = 0

    defer func() {
        //Les fonctions anonymes peuvent accéder aux variables de portée externe, il n'y a donc pas de problème
        counter <- c
        wg.Done()
        <-jc
    }()

    // loglevel=Affichage d'informations avec 2
    glog.V(2).Infof("[countWorker] start (offset: %d, read size: %d)\n", byteOffset, eachReadCount*buffersize)
    //Rouvrir le fichier cible
    //Le curseur de lecture de Seek est perturbé lors de l'utilisation du gestionnaire de fichiers d'origine
    f, err := os.OpenFile(filename, 0, 0)
    if err != nil {
        return
    }
    defer f.Close()

    //Déplacer vers la position de début de lecture spécifiée
    _, err = f.Seek(byteOffset, 0)
    if err != nil {
        return
    }

    //Vous pouvez également passer un bufio créé comme suit à getNumOfCharsOnIo
    //Cette fois io.Étant donné que la taille des données lues à partir de Reader peut être modifiée, elle n'est pas utilisée car elle est considérée comme ayant peu de mérite.
    // br := bufio.NewReaderSize(f, 1024*1024)

    c, err = getNumOfCharsOnIo(f, buffersize, eachReadCount)
    if err != nil {
        panic(err)
    }
}

getNumOfCharsOnIo()

Enfin, définissez getNumOfCharsOnIo (), qui compte en fait le nombre de lignes. Le processus est similaire au fameux article "io.Reader sukore", mais bytes.IndexByte () est ajouté à la partie qui compte les sauts de ligne. J'utilise. Je pense que c'est correct de considérer le mécanisme UTF-8, mais il peut être plus sûr d'utiliser Index Rune qui est commenté. Hmm. C'était la même chose par rapport au résultat de wc dans certains fichiers réels, mais il peut y avoir des cas où le résultat est différent.

// io.Lisez buffersize à partir de Reader et répétez le processus de comptage du nombre d'occurrences de répétition de targetStr.
func getNumOfCharsOnIo(r io.Reader, buffersize int, repeatCount int) (int, error) {
    //Initialiser le tampon de lecture
    buf := make([]byte, buffersize)

    //Variable pour stocker le nombre de lignes
    var c int = 0

    //À partir de la position de départ, lisez la chaîne d'octets par buffersize et affectez-la à buf
    for j := 0; j < repeatCount; j++ {
        n, err := r.Read(buf)
        //Si la taille de lecture est 0
        if n == 0 {
            return c, err
        }

        //Traitement en cas d'erreur de lecture
        if err != nil {
            return c, err
        }

        //Offset pour scanner le contenu du tampon
        of := 0

        //Traitement pour compter les sauts de ligne dans Buffer
        for {
            //La taille est spécifiée par n car buf est utilisé autour.
            // index := bytes.IndexRune(buf[of:n], rune('\n'))
            index := bytes.IndexByte(buf[of:n], '\n')

            //Après cela, quittez la boucle sans saut de ligne
            if index == -1 {
                break
            }

            // (Des sauts de ligne)Incrémenter le compteur
            c++

            //Poste de découverte+Avancer le décalage à 1
            of += index + 1
        }
    }

    return c, nil
}

La plupart des explications ont été laissées aux commentaires intégrés, mais c'est tout pour le code.

Le tout est ici

Exemple d'utilisation

Puisqu'il s'agit d'un programme qui prend des options, je vais brièvement vous montrer comment l'utiliser.

Afficher l'aide

> ./bin/go-lc --help
./bin/go-lc -f TARGETFILE [options] [glog options]
  -alsologtostderr
        log to standard error as well as files
  -b int
        (go-lc) Size of ReadBuffer (default 1048576)
  -f string
        (go-lc) Target File
  -log_backtrace_at value
        when logging hits line file:N, emit a stack trace
  -log_dir string
        If non-empty, write log files in this directory
  -logtostderr
        log to standard error instead of files
  -s int
        (go-lc) Num of File split (default 2)
  -stderrthreshold value
        logs at or above this threshold go to stderr
  -t int
        (go-lc) Max Num of Threads (default 2)
  -v value
        log level for V logs
  -vmodule value
        comma-separated list of pattern=N settings for file-filtered logging

Comptez le nombre de lignes pour le moment

> ./bin/go-lc -f /mnt/v01/resource/wikipedia/jawiki/20191001/extract/jawiki-20191001-categorylinks.sql
1428

Changez le niveau du journal et comptez le nombre de lignes tout en affichant divers

Par défaut, il est divisé en deux et exécuté en deux threads.

> ./bin/go-lc -f /mnt/v01/resource/wikipedia/jawiki/20191001/extract/jawiki-20191001-categorylinks.sql -v 5
I1216 20:47:23.781456   12091 main.go:233] Start
I1216 20:47:23.781785   12091 main.go:79] FileSize   : 1426087753 byte
I1216 20:47:23.781801   12091 main.go:80] Read buffer:    1048576 byte
I1216 20:47:23.781816   12091 main.go:81] Max Threads: 2
I1216 20:47:23.781826   12091 main.go:82] Split Num  : 2
I1216 20:47:23.781871   12091 main.go:160] [countWorker] start (offset: 713031680, read size: 714080256)
I1216 20:47:23.781953   12091 main.go:160] [countWorker] start (offset: 0, read size: 713031680)
I1216 20:47:23.957093   12091 main.go:115] [receiver] receive: 699
I1216 20:47:23.969989   12091 main.go:115] [receiver] receive: 729
I1216 20:47:23.970048   12091 main.go:242] End(188.280638ms)
1428

Il traite un fichier d'environ 1,4 Go en 0,188 seconde.

Compter en spécifiant le nombre de divisions (-s) et le nombre de threads (-t)

> ./bin/go-lc -f /mnt/v01/resource/wikipedia/jawiki/20191001/extract/jawiki-20191001-categorylinks.sql -v 5 -s 4 -t 4
I1216 20:51:51.827208   13285 main.go:233] Start
I1216 20:51:51.827519   13285 main.go:79] FileSize   : 1426087753 byte
I1216 20:51:51.827534   13285 main.go:80] Read buffer:    1048576 byte
I1216 20:51:51.827553   13285 main.go:81] Max Threads: 4
I1216 20:51:51.827565   13285 main.go:82] Split Num  : 4
I1216 20:51:51.827607   13285 main.go:160] [countWorker] start (offset: 1069547520, read size: 357564416)
I1216 20:51:51.827706   13285 main.go:160] [countWorker] start (offset: 713031680, read size: 356515840)
I1216 20:51:51.827646   13285 main.go:160] [countWorker] start (offset: 356515840, read size: 356515840)
I1216 20:51:51.827642   13285 main.go:160] [countWorker] start (offset: 0, read size: 356515840)
I1216 20:51:51.938578   13285 main.go:115] [receiver] receive: 343
I1216 20:51:51.939430   13285 main.go:115] [receiver] receive: 356
I1216 20:51:51.952839   13285 main.go:115] [receiver] receive: 386
I1216 20:51:51.956868   13285 main.go:115] [receiver] receive: 343
I1216 20:51:51.956899   13285 main.go:242] End(129.400448ms)
1428

Avec le fichier précédent, il est plus rapide à 0,129 seconde.

Essayez de changer la taille du tampon de lecture

> ./bin/go-lc -f /mnt/v01/resource/wikipedia/jawiki/20191001/extract/jawiki-20191001-categorylinks.sql -v 5 -s 4 -t 4 -
b 1024
I1216 20:53:02.522702   13459 main.go:233] Start
I1216 20:53:02.523194   13459 main.go:79] FileSize   : 1426087753 byte
I1216 20:53:02.523217   13459 main.go:80] Read buffer:       1024 byte
I1216 20:53:02.523222   13459 main.go:81] Max Threads: 4
I1216 20:53:02.523229   13459 main.go:82] Split Num  : 4
I1216 20:53:02.523275   13459 main.go:160] [countWorker] start (offset: 1069565952, read size: 356521984)
I1216 20:53:02.523351   13459 main.go:160] [countWorker] start (offset: 0, read size: 356521984)
I1216 20:53:02.523442   13459 main.go:160] [countWorker] start (offset: 356521984, read size: 356521984)
I1216 20:53:02.526218   13459 main.go:160] [countWorker] start (offset: 713043968, read size: 356521984)
I1216 20:53:03.146721   13459 main.go:115] [receiver] receive: 343
I1216 20:53:03.149466   13459 main.go:115] [receiver] receive: 386
I1216 20:53:03.186216   13459 main.go:115] [receiver] receive: 356
I1216 20:53:03.190404   13459 main.go:115] [receiver] receive: 343
I1216 20:53:03.190443   13459 main.go:242] End(667.278999ms)
1428

Il a été ralenti à 0,667 seconde en raison du tampon plus petit et de l'inefficacité.

résultat

En passant, je pense que certaines personnes s'inquiètent du résultat de l'écriture d'un traitement aussi inutile et de la rapidité avec laquelle il sera. En regardant l'exemple d'utilisation, le résultat de la taille de tampon 1048576 (1024 * 1024) de 4 divisions et 4 threads est bon.

Le résultat de la commande wc -l pour le même fichier est

time wc -l /mnt/v01/resource/wikipedia/jawiki/20191001/extract/jawiki-20191001-categorylinks.sql

(Première fois)
1428 /mnt/v01/resource/wikipedia/jawiki/20191001/extract/jawiki-20191001-categorylinks.sql
0.04user 0.26system 0:00.30elapsed 100%CPU (0avgtext+0avgdata 2104maxresident)k
0inputs+0outputs (0major+76minor)pagefaults 0swaps

(Deuxième fois)
time wc -l /mnt/v01/resource/wikipedia/jawiki/20191001/extract/jawiki-20191001-categorylinks.sql
1428 /mnt/v01/resource/wikipedia/jawiki/20191001/extract/jawiki-20191001-categorylinks.sql
0.03user 0.22system 0:00.26elapsed 99%CPU (0avgtext+0avgdata 2068maxresident)k
0inputs+0outputs (0major+75minor)pagefaults 0swaps

(Troisième fois)
1428 /mnt/v01/resource/wikipedia/jawiki/20191001/extract/jawiki-20191001-categorylinks.sql
0.03user 0.22system 0:00.26elapsed 99%CPU (0avgtext+0avgdata 2124maxresident)k
0inputs+0outputs (0major+75minor)pagefaults 0swaps

(4e)
1428 /mnt/v01/resource/wikipedia/jawiki/20191001/extract/jawiki-20191001-categorylinks.sql
0.04user 0.20system 0:00.25elapsed 99%CPU (0avgtext+0avgdata 2104maxresident)k
0inputs+0outputs (0major+78minor)pagefaults 0swaps

(5ème fois)
1428 /mnt/v01/resource/wikipedia/jawiki/20191001/extract/jawiki-20191001-categorylinks.sql
0.04user 0.23system 0:00.27elapsed 100%CPU (0avgtext+0avgdata 2068maxresident)k
0inputs+0outputs (0major+75minor)pagefaults 0swaps

moyenne: 0.268s

La moyenne de 5 fois était de 0,268 seconde.

L'environnement de la machine est entièrement Google Cloud Platform Compute Engine (n1-standard-4 (vCPU x 4, mémoire 15 Go)) et le fichier cible est un fichier sql Wikidump de 1,4 Go.

Cela a pris 0,129 seconde en 4 divisions, ce qui est mieux que la commande wc -l. Cela valait le gaspillage.

Notez s'il vous plaît

En fait, le résultat ci-dessus est probablement dû au cache de fichiers de GCE. Lorsque je l'ai essayé avec un autre fichier de 20 Go, cela a pris environ 3 minutes comme suit. Cette taille est également plus rapide que wc, mais il semble qu'elle puisse être plus rapide car elle traite 1,4 Go en 0,3 seconde. Par conséquent, des fichiers de plusieurs Go peuvent être mis en cache. En d'autres termes, il y a un risque qu'il y ait une différence d'efficacité avant et après la mise en cache. Et comme GCE a des disques montés sur le réseau, la vitesse dépend également des conditions du réseau. Veuillez consulter les résultats ci-dessus pour référence seulement.

Répertoriez les résultats de l'exécution de wc -l et de ce programme pour un fichier d'environ 20 Go.

> time wc -l /mnt/v01/resource/wikipedia/enwiki/20191001/extract/enwiki-20191001-categorylinks.sql

(wc 1ère fois)
19525 /mnt/v01/resource/wikipedia/enwiki/20191001/extract/enwiki-20191001-categorylinks.sql
0.91user 8.21system 3:58.40elapsed 3%CPU (0avgtext+0avgdata 2116maxresident)k
31893064inputs+0outputs (0major+75minor)pagefaults 0swaps

(wc deuxième fois)
19525 /mnt/v01/resource/wikipedia/enwiki/20191001/extract/enwiki-20191001-categorylinks.sql
0.86user 7.86system 3:09.32elapsed 4%CPU (0avgtext+0avgdata 2044maxresident)k
26220800inputs+0outputs (0major+77minor)pagefaults 0swaps

(go-lc 1ère fois)
bin/go-lc -f /mnt/v01/resource/wikipedia/enwiki/20191001/extract/enwiki-20191001-categorylinks.sql -v 5 -t 4 -s 4
I1216 21:19:05.381636   14202 main.go:233] Start
I1216 21:19:05.384584   14202 main.go:79] FileSize   : 20234931295 byte
I1216 21:19:05.384601   14202 main.go:80] Read buffer:    1048576 byte
I1216 21:19:05.384605   14202 main.go:81] Max Threads: 4
I1216 21:19:05.384609   14202 main.go:82] Split Num  : 4
I1216 21:19:05.384704   14202 main.go:160] [countWorker] start (offset: 15176040448, read size: 5059379200)
I1216 21:19:05.384733   14202 main.go:160] [countWorker] start (offset: 0, read size: 5058330624)
I1216 21:19:05.384786   14202 main.go:160] [countWorker] start (offset: 5058330624, read size: 5058330624)
I1216 21:19:05.384859   14202 main.go:160] [countWorker] start (offset: 10116661248, read size: 5059379200)
I1216 21:19:06.836037   14202 main.go:115] [receiver] receive: 4881
I1216 21:20:49.994339   14202 main.go:115] [receiver] receive: 4866
I1216 21:20:56.968630   14202 main.go:115] [receiver] receive: 4910
I1216 21:21:00.825423   14202 main.go:115] [receiver] receive: 4868
I1216 21:21:00.825466   14202 main.go:242] End(1m55.440902834s)
19525

(go-lc 2ème fois)
bin/go-lc -f /mnt/v01/resource/wikipedia/enwiki/20191001/extract/enwiki-20191001-categorylinks.sql -v 5 -t 4 -s 4
I1216 21:21:19.065087   14343 main.go:233] Start
I1216 21:21:19.066146   14343 main.go:79] FileSize   : 20234931295 byte
I1216 21:21:19.066164   14343 main.go:80] Read buffer:    1048576 byte
I1216 21:21:19.066169   14343 main.go:81] Max Threads: 4
I1216 21:21:19.066182   14343 main.go:82] Split Num  : 4
I1216 21:21:19.066232   14343 main.go:160] [countWorker] start (offset: 15176040448, read size: 5059379200)
I1216 21:21:19.066234   14343 main.go:160] [countWorker] start (offset: 0, read size: 5058330624)
I1216 21:21:19.066314   14343 main.go:160] [countWorker] start (offset: 5058330624, read size: 5058330624)
I1216 21:21:19.066377   14343 main.go:160] [countWorker] start (offset: 10116661248, read size: 5059379200)
I1216 21:21:20.477393   14343 main.go:115] [receiver] receive: 4881
I1216 21:23:04.790516   14343 main.go:115] [receiver] receive: 4910
I1216 21:23:35.783612   14343 main.go:115] [receiver] receive: 4868
I1216 21:23:53.859878   14343 main.go:115] [receiver] receive: 4866
I1216 21:23:53.859920   14343 main.go:242] End(2m34.793812658s)
19525

à la fin

Ce processus a également été créé comme un test pour traiter un gros fichier texte comme Wikidump à grande vitesse sans charger le tout.

Depuis que j'ai obtenu le gestionnaire de lecture séparément, j'ai essayé de monter 4 disques sur GCE, de copier le même fichier et de lire avec la distribution de disque, mais je m'attendais à ce que la vitesse de communication avec le NAS soit limitée. L'effet n'a pas été obtenu (c'était presque la même vitesse que lors de la lecture séparée avec une unité). GCS, qui est un service de stockage de GCP, prend en charge la lecture en unités d'octets, ou il peut être plus rapide d'effectuer une lecture fractionnée pour GCS. Cette zone semble avoir l'avantage d'io.Reader, ou l'avantage de Go qui permet de réutiliser le code en lisant à partir d'un fichier et via l'API GCS.

Merci de rester avec nous jusqu'à la fin de l'article qui semble redévelopper les roues de manière compliquée.

Recommended Posts

[Go language] Essayez de créer un compteur de lignes inutilement multithread
Essayez de sélectionner une langue
[Langage C] [Linux] Essayez de créer une simple commande Linux * Ajoutez simplement! !!
Essayez de créer une nouvelle commande sous Linux
Comment créer une boîte de saisie Kivy 1 ligne
Essayez de créer un module Python en langage C
Essayez de créer un Checkbutton dynamiquement avec Tkinter en Python
[Go] Comment créer une erreur personnalisée pour Sentry
Créer un serveur Web en langage Go (net / http) (1)
Essayez de créer un environnement python avec Visual Studio Code et WSL
Les utilisateurs de Rails essaient de créer un moteur de blog simple avec Django
[Go] Créez une commande CLI pour changer l'extension de l'image
Essayez de créer un type de service Web avec un langage de balisage 3D
[Langage C] Comment créer, éviter et créer un processus zombie
Créez une fonction pour obtenir le contenu de la base de données dans Go
Essayez de créer un article de Qiita avec l'API REST [Préparation environnementale]
Créez un outil de ligne de commande pour convertir des dollars en yens en utilisant Python
Essayez d'implémenter Yuma en langage Go
Essayez de dessiner une courbe de Bézier
Étapes pour créer un projet Django
Comment créer un package Conda
Comment créer un pont virtuel
Comment créer un Dockerfile (basique)
5 façons de créer un chatbot Python
Comment créer un fichier de configuration
Créer un bot LINE avec Django
[Python] [Word] [python-docx] Essayez de créer un modèle de phrase de mot en Python en utilisant python-docx
Quand je retourne en utilisant le chainer, ça va un peu
3. Traitement du langage naturel avec Python 1-2. Comment créer un corpus: Aozora Bunko
J'ai essayé de créer un linebot (implémentation)
Comment créer un clone depuis Github
Créer un bot pour retweeter les informations sur le virus corona
Comment créer un dossier git clone
J'ai essayé de créer un linebot (préparation)
Faisons un noyau jupyter
[GO language] Lisons le fichier YAML
[Python] [LINE Bot] Créer un robot LINE de retour de perroquet
Créer un compteur de fréquence de mots avec Python 3.4
Différentes façons de créer un dictionnaire (mémoires)
Essayez d'utiliser un langage de programmation probabiliste (Pyro)
Comment créer un référentiel à partir d'un média
Script pour créer un fichier de dictionnaire Mac
Créez un assembleur de langage synthétique de haut niveau. Partie 6
Les débutants ont essayé de créer une application Web native pour le cloud à l'aide de Datastore / GAE
Essayez de créer un site de gestion Todo en utilisant WebSocket avec Django (Swamp Dragon)
[LINE WORKS version Trello Bot] Comment créer un salon de discussion privé comprenant un robot de discussion