Domanda

Ambiente: OS X 10.8, GO 1.0.2

Faccio un canale con il buffer-size 2, quindi se scrivo il canale tre volte, lancerà un errore:

Trova: tutte le goroutine dormono - Deadlock!

Certo, è corretto.

MA Se scrivo canale quattro o più volte nelle goroutine, funziona bene, perché? La capacità del canale è 2, perché le goroutine lo ignorano o dimenticano l'impostazione della capacità? Commento i codici di lettura-canale, quindi nessuno leggerà il canale e salverà la capacità. Uso anche Time.Sleep per aspettare tutte le goroutine per finire il loro lavoro.

Si prega di rivedere i seguenti codici: pacchetto principale

//import "fmt"

func main() {
    c := make(chan int, 2)
    /*c <- 1
    c <- 2
    c <- 3*/
    for i:=0; i<4; i++ {
        go func(i int) {
            c <- i
            c <- 9
            c <- 9
            c <- 9
        }(i)
    }
    time.Sleep(2000 * time.Millisecond)

    /*for i:=0; i<4*2; i++ {
        fmt.Println(<-c)
    }*/
}

Qualcuno farebbe dei successi? grazie ragazzi.

È stato utile?

Soluzione

Quando un canale è buffer, ciò significa che non bloccerà fino a quando il buffer non sarà pieno. Una volta che il buffer è pieno, la goroutine di invio si bloccherà mentre cerca di aggiungere cose al canale.

Ciò significa che questo bloccerà:

c := make(chan int)
c <- 1          // Block here, this is unbuffered !
println(<-c)

E questo lo farà anche bloccare:

c := make(chan int, 2)
c <- 1
c <- 2
c <- 3           // Block here, buffer is full !
println(<-c)

Ma il punto di goroutine e canale è proprio quello di eseguire le cose contemporaneamente, quindi funzionerà:

c := make(chan int)
go func() { c <- 1; }() // This will block in the spawned goroutine until...
println(<-c)            // ... this line is reached in the main goroutine

E allo stesso modo:

c := make(chan int, 2)
go func() {  // `go ...` spawns a goroutine
    c <- 1   // Buffer is not full, no block
    c <- 2   // Buffer is not full, no block
    c <- 3   // Buffer is full, spawned goroutine is blocking until...
}()
println(<-c) // ... this line is reached in the main goroutine

Nel tuo esempio, generano quattro diverse goroutine, che scrivono tutte quattro numeri sullo stesso canale bufferico. Poiché il buffer è 2 <16, finiranno per bloccare

Ma il punto cruciale della questione è che la politica di Go Aspetta solo la goroutine principale:

L'esecuzione del programma inizia inizializzando il pacchetto principale e quindi invocando la funzione principale. Quando la funzione ritorna principale, il programma esce. Non aspetta il completamento di altre goroutine (non musicali).

Ciò significa che nel tuo primo esempio, il principale La goroutine stava bloccando quando ha raggiunto la linea c <- 3. Poiché nessun'altra goroutine è stata in grado di fare qualsiasi cosa che potesse potenzialmente sbloccare, il runtime ha rilevato che il programma è stato bloccato e ha riportato un errore.

Nel tuo secondo esempio, tuttavia, generato Il blocco delle goroutine, mentre il principale continua in silenzio fino a quando non raggiunge la fine della sua esecuzione, a quel punto tutte le (bloccate) le goroutine generate vengono uccise silenziosamente e non viene segnalato alcun errore.

Altri suggerimenti

Val ha dato una buona risposta. Vorrei aggiungere un suggerimento extra che ho trovato utile.

Quando si impara a utilizzare le goroutine, utilizzare canali a taglio a zero per iniziare. In questo modo, quando commetti un errore, otterrai immediatamente uno stallo, da cui puoi imparare. Devi imparare a scrivere un codice che non tocca a deadlock, il che significa apprendimento di trucchi come non avere dipendenze cicliche nelle relazioni client-server (supponendo che le tue goroutine siano scritte come clienti o server).

Il ragionamento sulla rete senza buffering è più semplice, anche se all'inizio questo potrebbe non essere ovvio.

Il buffering è davvero utile, ma dovrebbe essere considerato come un mezzo per migliorare le prestazioni.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top