2014-02-14 12 views
6

Ich versuche, einen Parser für eine große Menge an Datei zu erstellen, und ich kann Ressource nicht finden, was ich "verschachtelte Göroutinen" nennen kann (vielleicht ist das nicht der richtige Name?).Sollten wir verschachtelte Göroutinen machen?

Angesichts einer Menge von Dateien, jeder von ihnen hat viele Zeilen. Sollte ich:

for file in folder: 
    go do1 

def do1: 
    for line in file: 
     go do2 

def do2: 
    do_something 

Oder sollte ich nur „eine Ebene“ von goroutines, und gehen Sie wie folgt vor:

for file in folder: 
    for line in file: 
     go do_something 

Meine Frage Ziel in erster Linie Performance-Probleme.

Danke für das Erreichen dieses Satzes!

+0

Ist es so schwer, nur beides zu versuchen und zu sehen? Ich denke, es hängt stark von Ihrem Betriebssystem, Ihrer Festplatte und Ihrem Dateisystem ab. Zu wenig Parallelität bedeutet Blockieren des Wartens auf I/O, zu viel bedeutet Festplatten-Thrashing. – Thomas

+0

goroutines sind unabhängig voneinander geplant. Es spielt keine Rolle, ob Sie sie aus einer verschachtelten Schleife oder verschachtelten Funktionen aufrufen. Calling N goroutines ruft N goroutines an. – JimB

+1

IMHO gibt es andere bessere Werkzeuge für diese Art von Arbeitsplätzen geeignet, setzen Sie das weel nicht neu erfinden, schauen hadoop oder den Funken Projekt – fabrizioM

Antwort

5

Wenn Sie die von Ihnen angegebene Architektur durchlaufen haben, haben Sie eine gute Chance, CPU/Mem/etc zu verlieren, da Sie eine beliebige Anzahl an Arbeitern erstellen werden. Ich schlage vor, stattdessen mit einer Architektur zu gehen, die es ermöglicht, über Kanäle zu drosseln. Zum Beispiel:

In Ihrem Hauptprozess füttern Sie die Dateien in einen Kanal:

for _, file := range folder { 
    fileChan <- file 
} 

dann in eine andere goroutine die Dateien in Leitungen und speisen diese in einen Kanal brechen:

for { 
    select{ 
    case file := <-fileChan 
    for _, line := range file { 
     lineChan <- line 
    } 
    } 
} 

dann in eine dritte goroutine die Linien herauskommen und tun, was Sie mit ihnen tun werden:

for { 
    select{ 
    case line := <-lineChan: 
    // process the line 
    } 
} 

Der Hauptvorteil Das bedeutet, dass Sie so viele oder so wenige Routinen erstellen können, wie Ihr System es beherrscht und ihnen alle die gleichen Kanäle gibt und welche Routine auch immer zuerst an den Kanal geht, damit Sie den Betrag drosseln können der Ressourcen, die Sie verwenden.

Hier ist ein funktionierendes Beispiel: http://play.golang.org/p/-Qjd0sTtyP

+5

Das ist eine furchtbar umständlich und fehleranfällig Art und Weise 'für Zeile zu schreiben: = reiches lineChan {}' – Dustin

1

Die Antwort hängt davon ab, wie rechenintensive die Operation in jeder Zeile ist.

Wenn die Zeilenoperation nur von kurzer Dauer ist, sollten Sie auf keinen Fall eine Goroutine für jede Zeile erstellen.

Wenn es teuer ist (etwa 5 Sekunden oder mehr), fahren Sie mit Vorsicht fort. Möglicherweise haben Sie nicht genügend Arbeitsspeicher. Ab Go 1.4 weist das Erstellen einer Goroutine einen 2048-Byte-Stack zu. Für 2 Millionen Zeilen könnten Sie nur 2 GB RAM für die Goroutine-Stacks reservieren. Überlegen Sie, ob es sich lohnt, diesen Speicher zuzuweisen.

Kurz gesagt, werden Sie wahrscheinlich die besten Ergebnisse mit der folgenden Setup erhalten:

for file in folder: 
    go process_file(file) 

Wenn die Anzahl der Dateien die Anzahl der CPUs übersteigt, sind Sie wahrscheinlich genug Parallelität haben, um die Disk-I zu maskieren/O Latenz beim Lesen der Dateien von der Festplatte.

Verwandte Themen