Golang: Desmistificando 채널 - Conceito e sintaxe

소개



Resolvi fazer esse texto porque no meu primeiro contato com channels eu não entendi muito bem como funcionava, daí eu semper fugia para o WaitGroup 또는 fazia alguma Mutex para tentar resolver.

Fiz esse texto com o objetivo de deixar mais claro como usar channels e como entender os problemas comuns que você vai encontrar ao usar o channel de forma errada.

O que é e para que serve?



Channel, ou canal, é uma ferramenta nativa do para comunicar e sincronizar goroutines.

이 채널은 다양한 고루틴을 사용할 때 사용할 수 있는 뮤텍스를 사용할 수 없도록 주의를 기울이고 있습니다.

com 채널 você consegue facilmente fazer coisas como:
  • Coletar o resultado de várias goroutines fazendo requisições HTTP e ir mostrando na tela
  • Limitar seu servidor para processar no maximo 50 requisições concorrentemente
  • Fazer outras goroutines esperarem por um sinal que sua aplicação iniciou

  • Criando 및 usando 채널



    Para criar 음 채널, fazemos:

    func main() {
        ch := make(chan int)
    }
    


    O 채널은 기본적으로 다음과 같습니다: int , string , struct{} e outros.

    Esse tipo é o tipo de dado que vai ser enviado e recebido pelo canal.

    Ao enviar uma informação para um channel, o que o que o outro lado recebe é uma cópia do dado.

    Dessa forma você evita problemas de uma goroutine alterar o mesmo dado que outra goroutine pode estar lendo.

    Para enviar informações para um channel, fazemos:

    func main() {
        ch := make(chan string)
    
        ch <- "Shakespeare"
    }
    


    Para receber do channel, fazemos:

    func main() {
        ch := make(chan string)
    
        // recebendo de um channel e descartando valor
        <-ch
    
        // recebendo de um channel e guardando numa variável
        name := <-ch
    }
    


    어떤 기능이 있습니까?



    Se você rodar qualquer um dos códigos do exemplo anterior, vai acontecer isso:

    fatal error: all goroutines are asleep - deadlock!
    
    goroutine 1 [chan send]:
    main.main()
            main.go:5 +0x31
    exit status 2
    


    os 채널은 사용자가 수신할 수 있는 문제를 해결하기 위해 고루틴 실행을 일시 중지할 수 있습니다. Ou seja, a goroutine que tentar enviar vai esperar até que outra receba, e da mesma forma a goroutine que tentar receber vai esperar até que outra envie.

    No caso acima quando eu tento enviar para um channel, eu pauso a goroutine main para esperar que outra goroutine leia o que enviei, mas como não tem outra goroutine rodando, a main vai ficar esperando "para sempre"(deadlock ) ).

    O 런타임은 Go percebe que esse programa vai ficar parado indeterminadamente, porque todas as goroutines estão "dormindo"(all goroutines are asleep ), então ele encerra o programa com um código de erro.

    O mesmo acontece no segundo example.

    버퍼링된 채널에 존재하는 Também a gente enviar para um canal uma quantidade X de dados antes que ele comece a bloquear a goroutine, mas vamos ver isso mais para frente.

    우산도 채널 수정



    Para corrigir o problema do deadlock anterior, vamos criar outra goroutine que lê do channel, enquanto a goroutine main vai enviar para o channel.

    package main
    
    import (
        "fmt"
    )
    
    func main() {
        ch := make(chan int)
    
        // obs. 1: 'go' vai fazer com que essa função seja executada numa 
        // nova goroutine, então ler do channel não vai bloquear a main
    
        go func() {
            // obs. 2: eu não preciso passar o ch como parâmetro da função
            // porque o ch está no da main escopo
            <-ch
        }()
    
        // a goroutine main vai esperar até que consiga enviar
        ch <- 12
    
        fmt.Println("Fim")
    }
    


    Se você está confuso com ch <- 12 e <-ch , você pode pensar que a seta aponta para onde o dado está fluindo.

    // o dado está saindo do channel ch (receber) e sendo descartado
    <-ch
    
    // o dado está saindo do channel ch (receber) e sendo atribuído à variável x
    x := <-ch
    
    // o dado 12 está indo para o channel ch (enviar)
    ch <- 12
    

    좋은 웹페이지 즐겨찾기