2017-10-14 3 views
0

So habe ich eine Datei wie folgt zu lesen:Optimale Möglichkeit, eine Datei gleichzeitig in Go

NAME : a280 
COMMENT : drilling problem (Ludwig) 
TYPE : TSP 
DIMENSION: 280 
EDGE_WEIGHT_TYPE : EUC_2D 
NODE_COORD_SECTION 
    1 288 149 
    2 288 129 
    3 270 133 
    4 256 141 
    5 256 157 
    6 246 157 
    7 236 169 
    8 228 169 
    9 228 161 
10 220 169 
11 212 169 
12 204 169 
13 196 169 
14 188 169 
15 196 161 

und so weiter ...

Die Zahlen sind die Schnüre für Städte TSP zu lösen. Ich versuche das in Golang zu schreiben. Jetzt können die Instanzen wie 200 Städte oder sogar 40.000 Städte sein. Ich möchte die bestmögliche Lösung bekommen, also dachte ich, ich sollte diese Datei gleichzeitig verarbeiten. Ich habe folgenden Code bekommt:

package main 

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

func getCords(queue chan string) { 
    cords := regexp.MustCompile(`\s*\d+\s+\d+\s+\d+`) 
    for line := range queue { 
     if cords.MatchString(line) { 
      fmt.Println(line) 
     } 
    } 
} 

func readFile(fileName string) { 
    cords := make(chan string) 
    file := strings.NewReader(fileName) 
    go func() { 
     scanner := bufio.NewScanner(file) 
     for scanner.Scan() { 
      cords <- scanner.Text() 
     } 
     close(cords) 
    }() 
} 

// Menu - main program menu 
func Menu() { 
    reader := bufio.NewReader(os.Stdin) 
    fmt.Println("================== Projektowanie efektywnych algorytmów ==================") 
    fmt.Println("================== Zadanie nr 1 - Algorytm xyz    ==================") 
    // Wczytywanie pliku z danymi 
    // Format: Lp. X Y 
    fmt.Printf("\nPodaj nazwę pliku: ") 
    fileName, err := reader.ReadString('\n') 
    if err != nil { 
     fmt.Println(err) 
     return 
    } 
    readFile(fileName) 
} 

func main() { 
    Menu() 
} 

In Funktion getCords ich useregex benötigen, Cuz der Dateien sind in der Regel Informationsteil am Anfang haben.

Das Problem beginnt in readFile(). Ich starte eine Goroutine, die die Datei Zeile für Zeile durchsucht und alle Zeilen zum Kanal bringt. Natürlich startet die Ausführung einfach und geht weiter. Jetzt ist das Problem, nach dem go func() Anruf, ich würde versuchen müssen, vom Kanal zu lesen. Die Lösungen finde ich auf SO und im Internet waren wie folgt:

func readFile(fileName string) { 
    cords := make(chan string) 
    file := strings.NewReader(fileName) 
    go func() { 
     scanner := bufio.NewScanner(file) 
     for scanner.Scan() { 
      cords <- scanner.Text() 
     } 
     close(cords) 
    }() 
    for i := 0; i < 100; i++ { 
     go getCords(cords) 
    } 
} 

So te erste Ausführung von getCords würde nichts wahrscheinlich auch tun, weil die goroutine nicht die Linie zum Kanal, schnell zu bekommen würde verwalten. Die nächsten Iterationen würden wahrscheinlich den Job erledigen, aber das Problem ist, dass ich eine Nummer schreiben muss, wie 100 in diesem Beispiel, und es kann zu hoch sein, also wird der Kanal in 10 Iterationen geschlossen und danach ist es nur eine Verschwendung von Zeit oder es kann zu niedrig sein, und dann würde ich einfach nicht alle Ergebnisse bekommen.

Wie lösen Sie solche Probleme, Jungs? Gibt es einen optimalen Weg, oder muss ich bei einigen waitGroups bleiben?

+0

Start durch eine sequentielle Version zu schreiben, das funktioniert, dann erfahren Sie die langsamsten Teile des Programms Profilierung starten, öffnet sich schließlich Gleichzeitigkeit, um das Programm zu schreiben, an den entsprechenden Stellen. Außerdem https://github.com/AkshanshChahal/TSP-Golang –

+0

Sie öffnen keine Dateien irgendwo in Ihrem Code. 'file: = strings.NewReader (fileName)' öffnet und lädt keine Daten von 'fileName'. 'os.Open' macht das: https://golang.org/pkg/os/#Open. – abhink

Antwort

1

Ich denke ja, es wäre gut, sync.WaitGroup zu verwenden, um sicherzustellen, dass alle goroutines ihre Arbeit beendet haben. Eine mögliche Lösung:

func getCords(queue Chas string, wg sync.WaitGroup) { 
    defer wg.Done() 
    // your code 
} 

func readFile(fileName string) { 
    cords := make(chan string) 
    file := strings.NewReader(fileName) 

    go func() { 
     scanner := bufio.NewScanner(file) 
     for scanner.Scan() { 
      cords <- scanner.Text() 
     } 
     close(cords) 
    }() 

    wg := sync.WaitGroup{} 
    for i := 0; i < 100; i++ { 
     wg.Add(1) 
     go getCords(cords, wg) 
    } 
    wg.Wait() 
} 
+0

Aber eine Goroutine macht das ganze Lesen auf dem Kanal. Also wird diese Goroutine gestartet und die Ausführung geht weiter. Wo soll ich 'go getCords()' anrufen? – Frynio

+0

Ich habe den Code aktualisiert. Es ist kein Problem - weil auf 'cords <- scanner.Text()' geschrieben wird, wird blockiert. Weil es niemanden gibt, der aus dem Channel lesen kann, bis 'getCoords'-Goroutinen gestartet werden. Sie können diese beiden Blöcke auch tauschen: Starten Sie die "getCoords" der Benutzer, bevor Sie den producer - file reader starten. –

+0

Richtig, vergiss das Senden von Blöcken Goroutine, bis jemand aus dem Kanal liest. Muss ich 'wg' nicht mit dem Zeiger übergeben? Und warum machen Sie die for-Schleife für 100-Iterationen, wenn wir nicht wissen, wie viele Zeilen es lesen wird? – Frynio

Verwandte Themen