2017-05-05 1 views
0

Das Problem Code ist:golang Lesen und Schreiben von demselben Kanal

go func() { 
    defer wg.Done() 
    for { 
     task := <-tasks 

     if task.Attemts >= .5 { 
      tasks <- task # <- error 
     } 

     Println(task) 
    } 
}() 

Tasks mit tasks <- Task{"1", rand.Float64()} in einer anderen Schleife füllt.

Und jetzt haben wir haben Deadlock ...

Voll Beispiel: https://play.golang.org/p/s1pnb1Mu_Y

Der Punkt meines Codes ist - Web-scrapper erstellen, die man versuchen wird Urls nach analysieren ausfällt. Nehmen Sie einige Versuche und dann URL fallen.

Könnte in Golang sein wir haben einige mehr ideomische Weise, um dieses Problem zu lösen, denn ich weiß es nicht.

Antwort

1

Sie verwenden einen nicht gepufferten Kanal, wenn Sie versuchen, mit tasks <- task Ausführung in diesem Goroutine zu senden, wartet dort auf etwas anderes, um auf dem Kanal zu lesen. Da nichts anderes auf dem Kanal gelesen wird, kommt es zu einem Deadlock.

Die einzige Möglichkeit, diesen spezifischen Code zu verwenden, ist ein vollständig dedizierter Consumer oder ein gepufferter Kanal. Selbst mit einem gepufferten Kanal könnten Sie hier einen Deadlock bekommen, wenn der Puffer an dem Punkt voll wird, an dem Ihr einzelner Konsument versucht, darauf zu senden.

Wenn Sie wirklich von derselben goroutine senden müssen, müssen Sie eine neue goroutine spawnen, nur um sie zu senden. Etwas nach dem Vorbild von

go func() { 
    tasks <- task 
}() 

Oder man könnte so etwas wie diese:

requeue = make(chan Task) // could buffer if you want 
go func() { 
    for { 
     tasks <- requeue 
    } 
}() 
for { 
    task := <-tasks 

    if task.Attemts >= .5 { 
     requeue <- task 
    } 

    Println(task) 
} 

Umgang mit dem Schließen des Kanals und dergleichen natürlich.

+0

Das ist in meiner Antwort enthalten. – user3591723

0

Wenn dies das einzige goroutine-Lesen vom Kanal ist, kann es auch nicht darauf schreiben.

Es ist möglich, wenn Sie ein verwendet Kanal gepuffert, wäre es Art Arbeit für ein wenig, aber das nur Ihr Problem zurück schieben würde. Was Sie wirklich wollen, ist wahrscheinlich Verwendung

go func(){ 
    tasks <- task 
}() 

anstelle des einfachen tasks <- task. Dadurch wird das Schreiben in eine andere Goroutine ausgelagert, so dass diese direkt zum Lesen zurückkehren kann.