Ich kann die Angewohnheit, nutzlose Dinge zu produzieren, nicht loswerden. Dieses Mal schrieb ich einen Artikel über den Code des Zeilenzählers, der nutzlos multithreaded war.
Einige Dateien sind schneller als wc -l, was für diejenigen nützlich sein kann, die die Zeilen am schnellsten zählen möchten.
Go lernt alleine. Wir freuen uns auf Ihre Vorschläge zu Fehlern und besserem Schreiben.
"Parallelverarbeitung in Go-Sprache" (Warum haben Sie es nicht früher gelesen?) Rubbing io.Reader (Erzählen Sie mir von der Verborgenheit von Go?)
Zählt die Anzahl der Zeilen in der durch das Argument angegebenen Datei und zeigt sie auf dem Bildschirm an.
Die folgenden Werte können im Argument angegeben werden -Dateiname (-f) -Anzahl der Unterteilungen für geteiltes Lesen (-s) -Anzahl der Threads für die Parallelverarbeitung (-t) -Lesen Sie die Puffergröße (-b)
-Zählen Sie die Anzahl der Zeilen durch Multithread-Verarbeitung mit Goroutine und Kanälen -Rubben der Datei mit io.Reader (Reiben von io.Reader) -Verschieben Sie die Lesestartposition mit Suchen und teilen und lesen Sie die Datei nutzlos. ・ Es ist umweltfreundlich, da es den Lesepuffer direkt durchsucht.
Der allgemeine Verarbeitungsablauf ist wie folgt.
Der gesamte Code ist hier
Importieren Sie die erforderlichen Bibliotheken. Verwenden Sie das Flag, um Argumente und Glog für die Protokollierung zu erhalten.
package main
import (
"bytes"
"flag"
"fmt"
"io"
"math"
"os"
"sync"
"time"
"github.com/golang/glog"
)
Deklarieren Sie Variablen, indem Sie eine Struktur definieren, die Argumente empfängt.
// Arg is struct for commandline arg.
type Arg struct {
//Zu verarbeitende Datei
targetFile string
//Anzahl der Unterteilungen beim Zählen der Unterteilungen
splitNum int
//Threads laufen gleichzeitig(Maximal)Nummer
maxThreads int
//Puffergröße zum Lesen von Dateien
buffersize int
}
var (
arg Arg
)
Schreiben Sie den Argumenterweiterungsprozess usw. in die Init-Funktion.
Da Glog ein eigenes Argument verwendet, verwenden wir flag, um das eigene Argument von Glog neu zu definieren und zu initialisieren. Wenn die Befehlshilfe angezeigt wird, wird auch die Erklärung des Glog-Arguments angezeigt und ist verwirrend. Daher habe ich in die Argumenterklärung dieses Prozesses "(go-lc)" eingefügt, um sie zu unterscheiden (dieser Bereich ist intelligenter). Es scheint einen Weg zu geben, es zu schreiben.
func init() {
//Hilfemeldung einstellen
flag.Usage = func() {
fmt.Fprintf(os.Stderr, "%s\n", fmt.Sprintf("%s -f TARGETFILE [options] [glog options]",
os.Args[0]))
flag.PrintDefaults()
}
//Grundeinstellung des Loggers
_ = flag.Set("stderrthreshold", "INFO")
_ = flag.Set("v", "0")
//Festlegen von Befehlszeilenoptionen
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).")
}
Die Befehlshilfe in dieser Konfiguration wird wie folgt angezeigt: Die Hilfe von Glog ist ziemlich laut.
(Es ist laut, aber für ein kleines Tool ist es einfach, da Sie den Änderungsprozess der Protokollebene nicht selbst implementieren müssen.)
> ./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
Ich werde zuerst den Hauptprozess erklären. Es wird jedoch nur die Funktion getNumOfLines aufgerufen, die aggregiert, das Ergebnis empfängt und auf dem Bildschirm anzeigt.
func main() {
flag.Parse()
glog.V(1).Infof("Start")
//Starten Sie den Timer für die Berechnung der Verarbeitungszeit
startTime := time.Now()
//Führen Sie die Aggregationsverarbeitung aus
numOfLines, _ := getNumOfLines(arg.targetFile, arg.splitNum, arg.maxThreads, arg.buffersize)
//Bearbeitungszeit anzeigen
glog.V(1).Infof("End(%s)", time.Since(startTime))
fmt.Printf("%d\n", numOfLines)
}
getFileSize()
Eine Funktion zum Abrufen der Dateigröße. Siehe Kommentare zur Verarbeitung.
func getFileSize(filename string) (int, error) {
//Öffnen Sie die Zieldatei
fh, err := os.OpenFile(filename, 0, 0)
if err != nil {
return 0, err
}
defer fh.Close()
//Dateiinformationen abrufen
fileinfo, err := fh.Stat()
if err != nil {
return 0, err
}
//Ruft die Anzahl der Bytes in der Datei ab und gibt sie zurück
return int(fileinfo.Size()), nil
}
getNumOfLines()
Dies ist getNumOfLines (), das ich hauptsächlich gelesen habe. Es ist eine etwas lange Funktion, deshalb werde ich es separat erklären.
Der erste Teil berechnet die Anzahl der Pufferlesevorgänge für die gesamte Datei. Die folgende Formel.
*** Anzahl der Lesevorgänge = Dateigröße / Puffergröße (+1 wenn nicht teilbar) ***
func getNumOfLines(filename string, splitNum int, maxThreads int, buffersize int) (int, error) {
//Dateigröße abrufen
fsize, err := getFileSize(filename)
if err != nil {
return 0, err
}
// loglevel =Informationsanzeige mit 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)
//Berechnen Sie, wie oft es in Einheiten der Puffergröße gelesen werden kann.
var readCountTotal int = int(math.Trunc(float64(fsize) / float64(buffersize)))
//Wenn es einen Rest gibt, addieren Sie 1 zur Anzahl der Lesevorgänge
if fsize-(readCountTotal*buffersize) > 0 {
readCountTotal++
}
Als nächstes werden wir das Multithreading einrichten. Eine Wartegruppe ist möglicherweise nicht erforderlich, wenn Sie festlegen, wie der Kanal verwendet werden soll. Sie wird jedoch aus Gründen der Übersichtlichkeit verwendet.
//Initialisieren Sie die Endwartegruppe
wg := &sync.WaitGroup{}
//Kanal zur Begrenzung der Anzahl gleichzeitiger Goroutine-Läufe
jc := make(chan interface{}, maxThreads)
defer close(jc)
//Kanal zum Empfangen des Zeilenzählungsergebnisses jeder Goroutine
counterCh := make(chan int, maxThreads)
//Vom Ende der Standby-Goroutine jeder Goroutine
//Kanal für die Rückgabe aggregierter Ergebnisse an die Hauptverarbeitung
resultCh := make(chan int)
defer close(resultCh)
//Starten Sie Goroutine, um Ergebnisse zu erhalten
//Die Endbedingung ist nahe(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)
Dies ist eine Schleife, die Goroutine (countWorker) startet, die die Anzahl der Zeilen zählt. byteOffset ist die Lesestartposition. EachReadCount gibt an, wie oft der Puffer gelesen wurde, die Berechnungsmethode stammt jedoch von der folgenden Site. Teilen Sie n ganze Zahlen so gleichmäßig wie möglich auf Einige Leute sind schlau.
Ein Kanal namens jc wird verwendet, um die Anzahl der gleichzeitigen Starts zu steuern. Es ist eine Standardverwendung, aber ich denke, die folgende URL wird hilfreich sein. So steuern Sie die maximale Anzahl von Goroutinen Begrenzen Sie die Anzahl der parallelen Prozesse entsprechend der Anzahl der CPUs in der Go-Sprache Übrigens verwenden die beiden oben genannten Sites den Bool-Typ und den Int-Typ, aber laut "Parallelverarbeitung durch Go-Sprache (O'Reilly)" ist "Eine Schnittstelle mit einer Kapazität von 0 gut für den Kanal zur Steuerung der Anzahl der Starts!" Das ist.
//Anzahl der Zeilen Anzahl Startposition für die Übergabe an die Goroutine(0 ist#Für 1 Goroutine)
var byteOffset int64 = 0
//Zeilenzählschleife zum Starten der Goroutine
for i := 0; i < splitNum; i++ {
//Wie oft muss der Puffer in countLinesInThread gelesen werden?
eachReadCount := int(math.Trunc(float64(readCountTotal+i) / float64(splitNum)))
//Füllen Sie ein Goroutine-Startnummernarray
jc <- true
//Erhöhen Sie die Wartegruppe um eins
wg.Add(1)
//Startlinienzählung Goroutine
go countWorker(filename, eachReadCount, byteOffset, buffersize, wg, jc, counterCh)
//Vorab-Leseversatz
byteOffset += int64(eachReadCount * buffersize)
}
wg.Wait()
close(counterCh)
return <-resultCh, nil
}
countWorker()
Definieren Sie als Nächstes countWorker (), den Hauptteil von Goroutine. Eigentlich öffne ich einfach die durch Dateiname angegebene Datei, verschiebe die Leseposition mit f.Seek und lese dann getNumOfCharsOnIo. Der Teil, der dieselbe Datei mehrmals öffnet, scheint etwas überflüssig zu sein, aber da es einen Suchprozess für das geteilte Lesen gibt, mache ich dies (Ist es sinnvoll, hier zu teilen? Ich habe ein Gefühl, aber es ist mir egal In einigen Fällen ist es wichtig, die ersten Absichten am Entwicklungsstandort für Erwachsene zu haben.
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() {
//Anonyme Funktionen können auf Variablen des äußeren Bereichs zugreifen, sodass dies kein Problem darstellt
counter <- c
wg.Done()
<-jc
}()
// loglevel=Informationsanzeige mit 2
glog.V(2).Infof("[countWorker] start (offset: %d, read size: %d)\n", byteOffset, eachReadCount*buffersize)
//Öffnen Sie die Zieldatei erneut
//Der Lesecursor von Seek wird durch die Verwendung des ursprünglichen Dateihandlers durcheinander gebracht
f, err := os.OpenFile(filename, 0, 0)
if err != nil {
return
}
defer f.Close()
//Gehen Sie zur angegebenen Lesestartposition
_, err = f.Seek(byteOffset, 0)
if err != nil {
return
}
//Sie können auch ein wie folgt erstelltes Bufio an getNumOfCharsOnIo übergeben
//Diesmal io.Da die Größe der vom Reader gelesenen Daten geändert werden kann, wird sie nicht verwendet, da sie als wenig wertvoll angesehen werden.
// br := bufio.NewReaderSize(f, 1024*1024)
c, err = getNumOfCharsOnIo(f, buffersize, eachReadCount)
if err != nil {
panic(err)
}
}
getNumOfCharsOnIo()
Definieren Sie abschließend getNumOfCharsOnIo (), das tatsächlich die Anzahl der Zeilen zählt. Der Vorgang ähnelt dem berühmten Artikel "io.Reader Susukore", aber bytes.IndexByte () wird dem Teil hinzugefügt, der Zeilenumbrüche zählt. Ich benutze. Ich denke, es ist in Ordnung, wenn man den UTF-8-Mechanismus berücksichtigt, aber es ist möglicherweise sicherer, Index Rune zu verwenden, das auskommentiert ist. Hmm. Im Vergleich zum Ergebnis von wc in einigen realen Dateien war es dasselbe, aber es kann Fälle geben, in denen das Ergebnis unterschiedlich ist.
// io.Lesen Sie die Puffergröße aus dem Reader und wiederholen Sie den Vorgang des Zählens der Anzahl der Vorkommen von targetStr repeatCount-Zeiten.
func getNumOfCharsOnIo(r io.Reader, buffersize int, repeatCount int) (int, error) {
//Lesepuffer initialisieren
buf := make([]byte, buffersize)
//Variable zum Speichern der Anzahl der Zeilen
var c int = 0
//Lesen Sie von der Startposition aus die Byte-Zeichenfolge in Puffergröße und weisen Sie sie buf zu
for j := 0; j < repeatCount; j++ {
n, err := r.Read(buf)
//Wenn die Lesegröße 0 ist
if n == 0 {
return c, err
}
//Verarbeitung beim Lesefehler
if err != nil {
return c, err
}
//Offset zum Scannen des Pufferinhalts
of := 0
//Verarbeitung zum Zählen von Zeilenumbrüchen im Puffer
for {
//Die Größe wird durch n angegeben, da buf verwendet wird.
// index := bytes.IndexRune(buf[of:n], rune('\n'))
index := bytes.IndexByte(buf[of:n], '\n')
//Verlassen Sie danach die Schleife ohne Zeilenumbrüche
if index == -1 {
break
}
// (Von Zeilenumbrüchen)Erhöhen Sie den Zähler
c++
//Entdeckungsposition+Vorabversatz auf 1
of += index + 1
}
}
return c, nil
}
Der größte Teil der Erklärung wurde Inline-Kommentaren überlassen, aber das ist alles für den Code.
Das Ganze ist hier
Da es sich um ein Programm handelt, das Optionen enthält, werde ich kurz zeigen, wie es verwendet wird.
> ./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
> ./bin/go-lc -f /mnt/v01/resource/wikipedia/jawiki/20191001/extract/jawiki-20191001-categorylinks.sql
1428
Standardmäßig ist es zweigeteilt und wird in zwei Threads ausgeführt.
> ./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
Es verarbeitet eine Datei von ca. 1,4 GB in 0,188 Sekunden.
> ./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
Mit der vorherigen Datei ist es schneller auf 0,129 Sekunden.
> ./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
Es wurde aufgrund des kleineren Puffers und der Ineffizienz auf 0,667 Sekunden verlangsamt.
Übrigens denke ich, dass einige Leute besorgt sind über das Ergebnis des Schreibens solch nutzloser Verarbeitung und wie schnell es sein wird. Im Verwendungsbeispiel ist das Ergebnis der Puffergröße 1048576 (1024 * 1024) von 4 Unterteilungen und 4 Threads gut.
Das Ergebnis des Befehls wc -l für dieselbe Datei lautet
time wc -l /mnt/v01/resource/wikipedia/jawiki/20191001/extract/jawiki-20191001-categorylinks.sql
(Erstes Mal)
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
(Zweites Mal)
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
(Drittes Mal)
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
(4 ..)
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. Mal)
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
durchschnittlich: 0.268s
Der Durchschnitt von 5 Mal betrug 0,268 Sekunden.
Die Computerumgebung besteht ausschließlich aus Google Cloud Platform Compute Engine (n1-Standard-4 (vCPU x 4, Speicher 15 GB)), und die Zieldatei ist eine Wikidump-SQL-Datei mit 1,4 GB.
Es dauerte 0,129 Sekunden in 4 Divisionen, was besser ist als der Befehl wc -l. Es war die Verschwendung wert.
Tatsächlich ist das obige Ergebnis wahrscheinlich auf den Datei-Cache von GCE zurückzuführen. Als ich es mit einer anderen 20-GB-Datei versuchte, dauerte es ungefähr 3 Minuten wie folgt. Diese Größe ist auch schneller als wc, aber es scheint, dass es schneller sein kann, weil es 1,4 GB in 0,3 Sekunden verarbeitet. Daher können Dateien mit mehreren GB zwischengespeichert werden. Mit anderen Worten, es besteht das Risiko, dass es vor und nach dem Zwischenspeichern zu einem Unterschied in der Effizienz kommt. Und da GCE Festplatten über das Netzwerk bereitgestellt hat, hängt die Geschwindigkeit auch von den Netzwerkbedingungen ab. Bitte beachten Sie die obigen Ergebnisse nur als Referenz.
Listen Sie die Ergebnisse der Ausführung von wc -l und dieses Programms für eine Datei von ca. 20 GB auf.
> time wc -l /mnt/v01/resource/wikipedia/enwiki/20191001/extract/enwiki-20191001-categorylinks.sql
(wc 1. mal)
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 zweites mal)
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. mal)
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. mal)
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
Dieser Prozess wurde auch als Test erstellt, um eine große Textdatei wie Wikidump mit hoher Geschwindigkeit zu verarbeiten, ohne das Ganze zu laden.
Da ich den Read-Handler separat erhalten habe, habe ich versucht, 4 Festplatten auf GCE zu mounten, dieselbe Datei zu kopieren und mit Festplattenverteilung zu lesen, aber ich habe erwartet, dass die Kommunikationsgeschwindigkeit mit NAS begrenzt ist. Der Effekt wurde nicht erzielt (es war fast die gleiche Geschwindigkeit wie beim separaten Lesen mit einer Einheit). GCS, ein Speicherdienst von GCP, unterstützt das Einlesen von Byteeinheiten, oder es kann schneller sein, ein geteiltes Lesen für GCS durchzuführen. Dieser Bereich scheint den Vorteil von io.Reader oder den Vorteil von Go zu haben, mit dem Sie den Code durch Lesen aus einer Datei und über die GCS-API wiederverwenden können.
Vielen Dank, dass Sie bis zum Ende des Artikels bei uns bleiben, der die Räder auf komplizierte Weise neu zu entwickeln scheint.
Recommended Posts