2016-08-08 10 views
1
package main 

import (
    "os" 
    "sync" 
) 

func main() { 
    var wg sync.WaitGroup 
    wg.Add(1024 * 1024) 
    for i := 0; i < (1024 * 1024); i++ { 
     go func(index int) { 
      if f, e := os.Open(i); e == nil { 
       //blah blah 
       f.Close() 
      } 
     }(i) 
    } 
    wg.Done() 
} 

Wenn Sie das Programm ausführen, wird der folgende Fehler angezeigt. "Öffnen $ zu viele offene Dateien" Bitte sagen Sie uns, wie Sie den Fehler beheben können.Golang zu viele offene Dateien in Go-Funktion, Goroutine

+8

die Antwort nicht verwandt ist gehen, aber lesen Die Manpage für "ulimit". Allerdings - a. Sie Code hat zwei katastrophale Bugs, sehen Sie, ob Sie sie erkennen. Und b. Darüber hinaus versuchen Sie, 1M Dateien auf einmal zu öffnen, es sei denn, Sie haben eine massive RAID Array ist das nicht praktikabel –

+0

Was ist Ihr Betriebssystem, ist es Unix/Linux? – kopiczko

+0

ulimit ist nicht die beste Lösung. Ich würde lieber nur eine begrenzte Anzahl von goroutines haben, die Dateien öffnen und verarbeiten (vielleicht 500 parallel geöffnete Dateien) Und jede Goroutine sollte Eingaben von demselben Kanal auswählen, öffnet t er Datei, lesen und schließen Sie es, und schickte das Ergebnis zurück zu anderen Kanal. Dieser zweite Kanal sollte Teil der Anfrage sein. Und jeder, der diese Goroutine benutzen soll, sollte diesen Kanal erstellen, eine Anfrage senden und auf das Ergebnis warten. Verstehst du, oder du brauchst ein Beispiel? – lofcek

Antwort

4

Sie haben keine Systemressourcen mehr, weil Sie zu viele Dateideskriptoren verwenden, ohne genügend zu veröffentlichen. Sie müssen die Nebenläufigkeit in Ihrem Programm einschränken.

Dazu können Sie einen gepufferten Kanal haben, der als Zähl-Semaphor fungiert.

sem := make(chan struct{}, 12) // 12 is the maximum number of 
           // concurrent processes that may run at any time 

Jetzt können Sie Ihre Methode ändern, wie:

func main() { 
    var wg sync.WaitGroup 
    wg.Add(1024 * 1024) 

    for i := 0; i < (1024 * 1024); i++ { 
     go func(index int) { 

      // if there are already 12 goroutines running, below send will block 
      // and a new file wont be open 
      sem <- struct{}{} 

      // once this goroutine finishes, empty the buffer by one 
      // so the next process may start (another goroutine blocked on 
      // above send will now be able to execute the statement and continue) 
      defer func() { <-sem }() 

      // wg.Done must be deferred after a read from sem so that 
      // it executes before the above read 
      defer wg.Done() 

      if f, e := os.Open(strconv.Itoa(index)); e != nil { 
       // handle file open failure 
       return 
      } 
      defer f.Close() 
      // handle open file 
     }(i) 
    } 

    wg.Wait() 
    close(sem) 
} 

Ihre Nutzung von wg.Done auch falsch ist. Lesen Sie mehr über sie here

(Beachten Sie, dass dieser Code eine grundlegende Vorstellung über diese Art von Problem geben Sie auch auf diese Frage für ein Arbeitsbeispiel beziehen. Go worker pool with repetitive queue structure

+0

Dies hat immer noch die zwei Bugs der ursprünglichen Frage: 1. Die Goroutine-Funktion bezieht sich auf "i" und nicht auf "index", das an sie übergeben wird, und führt dazu, die falschen Dateien zu öffnen (neben der Tatsache, dass Sie können) t öffne Ganzzahlen als Dateien). 2. Fügen Sie der waitGroup noch 1024 * 1024 hinzu, während Sie 'Done()' nur einmal machen :) –

+0

Der Index-Fehler wurde aktualisiert. Vielen Dank. Über das 'wg.Done', was meinst du es wird nur einmal gemacht? Jede Goroutine muss es nur einmal tun, und genau das passiert. Kannst du bitte ein bisschen mehr erklären. – abhink

+0

Nein, es ist in Ordnung, Sie haben es behoben. Der Code in der Frage selbst hat diesen Fehler. –

Verwandte Themen