Pergunta

Ambiente: OS X 10.8, Go 1.0.2

Faço um canal com o tamanho do buffer 2; se eu escrever o canal três vezes, ele lançará erro:

Jogo: Todas as goroutinas estão dormindo - Deadlock!

Claro, está correto.

MAS Se eu escrever o canal quatro ou mais vezes nas goroutinas, funciona bem, por quê? A capacidade do canal é 2, por que as goroutinas ignoram isso ou esquecem a configuração de capacidade? Comentei os códigos de canal de leitura, para que ninguém leia o canal e salve a capacidade. Eu também uso o tempo.

Por favor, revise os seguintes códigos: Package Main

//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)
    }*/
}

Alguém por favor daria alguns hits? obrigado rapazes.

Foi útil?

Solução

Quando um canal é buffer, isso significa que não bloqueará até que o buffer esteja cheio. Quando o buffer estiver cheio, o Goroutine de envio será bloqueado, pois tenta adicionar coisas ao canal.

Isso significa que isso vai bloquear:

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

E isso vai também quadra:

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

Mas o ponto de Goroutines e Channel é precisamente executar as coisas simultaneamente, então isso funcionará:

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 da mesma forma:

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

No seu exemplo, você gera quatro goroutinas diferentes, que escrevem quatro números no mesmo canal em buffer. Como o buffer é 2 <16, eles acabarão bloqueando

Mas o cerne da questão é que a política Go é para Espere apenas a goroutina principal:

A execução do programa começa inicializando o pacote principal e a invocando a função principal. Quando a função principal retorna, o programa sai. Não espera que outras goroutinas (não principais) sejam concluídas.

Isso significa que em seu primeiro exemplo, o a Principal Goroutine estava bloqueando quando atingiu a linha c <- 3. Como nenhum outro goroutine foi capaz de fazer qualquer coisa que pudesse desbloqueá -lo, o tempo de execução detectou que o programa foi impulsionado e relatou um erro.

No seu segundo exemplo, no entanto, gerado O bloqueio de Goroutines, enquanto o principal continua silenciosamente até chegar ao final de sua execução, momento em que todas as goroutinas (bloqueadas) geradas são mortas silenciosamente e nenhum erro é relatado.

Outras dicas

Val deu uma boa resposta. Eu gostaria de adicionar uma dica extra que achei útil.

Ao aprender a usar goroutines, use canais com buffer zero para começar. Dessa forma, quando você cometer um erro, você terá imediatamente um impasse, com o qual pode aprender. Você precisa aprender a escrever código que não seja encaixado, o que significa aprender truques como não ter dependências cíclicas nos relacionamentos com o cliente-servidor (supondo que seus goroutines sejam escritos como clientes ou servidores).

O raciocínio sobre a rede sem buffer é mais simples, embora isso possa não ser óbvio a princípio.

O buffer é realmente útil, mas deve ser considerado como um meio de melhorar o desempenho.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top