Wie kann man prüfen, ob ein Kanal geschlossen ist oder nicht, ohne ihn zu lesen?
Dies ist ein gutes Beispiel der Arbeitnehmer & controller-Modus in Go geschrieben von @Jimt, in Antwort auf
"Gibt es eine elegante Möglichkeit, um zu pausieren & resume andere goroutine in golang?"
package main
import (
"fmt"
"runtime"
"sync"
"time"
)
//Possible worker states.
const (
Stopped = 0
Paused = 1
Running = 2
)
//Maximum number of workers.
const WorkerCount = 1000
func main() {
//Launch workers.
var wg sync.WaitGroup
wg.Add(WorkerCount + 1)
workers := make([]chan int, WorkerCount)
for i := range workers {
workers[i] = make(chan int)
go func(i int) {
worker(i, workers[i])
wg.Done()
}(i)
}
//Launch controller routine.
go func() {
controller(workers)
wg.Done()
}()
//Wait for all goroutines to finish.
wg.Wait()
}
func worker(id int, ws <-chan int) {
state := Paused //Begin in the paused state.
for {
select {
case state = <-ws:
switch state {
case Stopped:
fmt.Printf("Worker %d: Stopped\n", id)
return
case Running:
fmt.Printf("Worker %d: Running\n", id)
case Paused:
fmt.Printf("Worker %d: Paused\n", id)
}
default:
//We use runtime.Gosched() to prevent a deadlock in this case.
//It will not be needed of work is performed here which yields
//to the scheduler.
runtime.Gosched()
if state == Paused {
break
}
//Do actual work here.
}
}
}
//controller handles the current state of all workers. They can be
//instructed to be either running, paused or stopped entirely.
func controller(workers []chan int) {
//Start workers
for i := range workers {
workers[i] <- Running
}
//Pause workers.
<-time.After(1e9)
for i := range workers {
workers[i] <- Paused
}
//Unpause workers.
<-time.After(1e9)
for i := range workers {
workers[i] <- Running
}
//Shutdown workers.
<-time.After(1e9)
for i := range workers {
close(workers[i])
}
}
Aber dieser code hat auch ein Problem: Wenn Sie entfernen möchten, ein Arbeiter-Kanal in workers
wenn worker()
beendet, dead lock passiert.
Wenn Sie close(workers[i])
nächsten mal-controller schreibt in es wird eine Panik verursachen, da gehen Sie nicht schreiben können in einem geschlossenen Kanal. Wenn Sie eine mutex zu schützen, dann wird es fest auf workers[i] <- Running
da die worker
ist lese nicht alles von den Kanal und schreiben werden gesperrt, und mutex dazu, dass ein dead lock. Sie können auch geben Sie einen größeren Puffer ein Kanal als work-around, aber es ist nicht gut genug.
So, ich denke, der beste Weg, dies zu lösen, ist worker()
engen Kanal, wenn beendet, wenn der controller einen Kanal gefunden hat, geschlossen ist, überspringen Sie es und tun nichts. Aber ich kann nicht herausfinden, wie um zu überprüfen, ein Kanal ist bereits geschlossen, oder nicht in dieser situation. Wenn ich versuche zu Lesen, den Kanal-controller, der controller blockiert werden. Also ich bin sehr verwirrt jetzt.
PS: die Wiederherstellung der erhabene Panik ist, was ich versucht habe, aber es wird in der Nähe goroutine die Panik ausgelöst. In diesem Fall wird es controller, so dass es keine Verwendung.
Immer noch, ich denke, es ist nützlich für Go-team zu implementieren Sie diese Funktion in der nächsten version Gehen.
InformationsquelleAutor der Frage Reck Hou | 2013-04-19
Du musst angemeldet sein, um einen Kommentar abzugeben.
In einem hacky Art, wie es getan werden kann für die Kanäle, die man versucht zu schreiben, um durch der Wiederherstellung von dem erhabenen Panik. Aber Sie kann nicht überprüfen, ob eine lese-Kanal wird geschlossen, ohne zu Lesen.
Entweder Sie
v <- c
)v, ok <- c
)v, ok <- c
)v <- c
)Nur das Letzte technisch nicht Lesen aus dem Kanal, aber das ist von wenig nutzen.
InformationsquelleAutor der Antwort zzzz
Gibt es keine Möglichkeit zu schreiben, eine sichere Anwendung, wo Sie brauchen, um zu wissen, ob ein Kanal offen ist, ohne mit dieser zu interagieren.
Der beste Weg, das zu tun, was Sie wollen, sind zu tun, ist mit zwei Kanälen-eine für die Arbeit und eine, um anzuzeigen, ein Wunsch, den Status ändern (sowie die Beendigung dieser Zustand ändern, wenn das wichtig ist).
Kanäle sind Billig. Komplexe design überlastung Semantik nicht.
[auch]
ist wirklich verwirrend und nicht-offensichtliche Art und Weise zu schreiben
Dinge einfach halten und jeden (auch Sie) Sie verstehen kann.
InformationsquelleAutor der Antwort Dustin
Ich weiß, diese Antwort ist so spät, ich schrieb diese Lösung, Hacking Gehen Sie run-time, Es ist nicht die Sicherheit, kann Es Abstürze:
https://gist.github.com/youssifsayed/ca0cfcf9dc87905d37a4fee7beb253c2
InformationsquelleAutor der Antwort youssif
Vielleicht bin ich etwas fehlt, aber es scheint, dass die einfache und richtige Weise zu handhaben, ist zu senden "gestoppt", um den Kanal (das beendet die go-routine), schließen Sie den Kanal und stellen Sie es auf null.
Wenn Sie denken, Sie brauchen, um zu überprüfen, für einen geschlossenen Kanal, ohne es zu Lesen, dann gibt es ein problem mit Ihrem design. (Beachten Sie, dass es andere Probleme mit dem code, wie das "busy-looping" pausiert Arbeiter.)
InformationsquelleAutor der Antwort Andrew W. Phillips
Aus der Dokumentation:
Einen Kanal geschlossen werden kann mit der eingebauten Funktion schließen. Der multi-valued-Zuordnung form des erhalten Betreiber meldet, ob ein empfangener Wert, der gesendet wurde, bevor der Kanal geschlossen wurde.
https://golang.org/ref/spec#Receive_operator
Beispiel von Golang in Aktion zeigt dieser Fall:
InformationsquelleAutor der Antwort Israel Barba
Gut, können Sie verwenden
default
Zweig, ihn zu erkennen, für einen geschlossenen Kanal ausgewählt werden, zum Beispiel: der folgende code wähltdefault
,channel
,channel
, die erste wählen, ist nicht gesperrt.InformationsquelleAutor der Antwort kcats
Wenn Sie hören Sie diesen Kanal, den Sie immer können findout, dass der Kanal geschlossen wurde.
Aber denken Sie daran, Sie können nicht in der Nähe eines Kanals zwei mal. Dieser löst Panik.
InformationsquelleAutor der Antwort jurka
ist es einfacher, zunächst zu prüfen, ob der Kanal hat Elemente, die Sicherstellung der Kanal aktiv ist.
InformationsquelleAutor der Antwort Enric