Golang: Desmistificando 채널 - Exemplo concreto

구체적인 채널 사용 예



Vamos supor que você tenha um slice de URLs de arquivos e queira baixar todos de forma simultânea.

Você pode começar implementando uma solução sequencial, e depois fazer isso concorrente com goroutines, e por último usar os os channels para esperar cada download terminar e comunicar que eles finalizaram.

Fazendo os는 순차 형식으로 다운로드합니다.



Digamos que você tenha um slice com os arquivos que quer baixar:

urls := []string{
    "http://files.com/file1.png",
    "http://files.com/file2.png",
    "http://files.com/file3.png",
}


Para fazer or download deles, você pode criar uma função download que recebe URL do arquivo e faz o download.

Para simular o download, vamos fazer uma função que espera um tempo aleatório entre 0 e 3 segundos.

func download(url string) {
    r := rand.Intn(4)
    time.Sleep(time.Duration(r) * time.Second)
}


Agora, vamos fazer 또는 파일 형식 순차 파일 다운로드:

for _, url := range urls {
    download(url)
    fmt.Println("concluído:", url)
}


O resultado vai ser esse:

concluído: http://files.com/file1.png
concluído: http://files.com/file2.png
concluído: http://files.com/file3.png


다운로드할 수 있는 프로그램이 3개 단계가 없으며 총 9개 단계가 있습니다.

Se conseguirmos fazer isso de forma simultânea, o pior cenário vai levar 3 segundos no total.

Usando goroutines para fazer 다운로드 동시 다운로드


  • Criamos um channel de string

  • finished := make(chan string)
    


    Poderia ser de outro tipo, mas nesse caso vou mandar a URL do download que finalizou, por isso vou usar um chan string .
  • Numa nova goroutine 다운로드 시작

  • func download(url string) {
        ...
    }
    
    func main () {
        urls := []string{
            ...
        }
    
        finished := make(chan string)
    
        for _, url := range urls {
            // isso é feito pra redefinir a url nesse escopo
            url := url
    
            go download(url)
        }
    }
    


    Isso não vai funcionar, porque a goroutine main Vai finalizar primeiro e vai encerrar o programa.
  • Quando o 다운로드 finalizar, vamos enviar para o channel a URL

  • func download(url string) {
        ...
    }
    
    func downloadAndNotify(url string, ch chan string) {
        download(url)
    
        // agora em vez de só baixar em outra goroutine, estamos
        // enviando a url do download finalizado para o channel
        ch <- url
    }
    
    func main () {
        ...
    
        for _, url := range urls {
            url := url
            go downloadAndNotify(url, finished)
        }
    
        // obs.: o programa vai continuar encerrando antes de fazer os downloads
    }
    


  • Recebemos os valores do 채널

  • func main () {
        ...
    
        for _, url := range urls {
            url := url
            go downloadAndNotify(url, finished)
        }
    
        // sabemos que o números de resultados vai ser igual ao 
        // tamanho de urls, então podemos fazer esse for para repetir len(urls) vezes
        for range urls {
    
            // recebemos um resultado do channel
            // lembre-se, esse receber vai bloquear até que alguma goroutine envie algo
            url := <-finished
    
            fmt.Println("concluído:", url)
        }
    
        // como o loop anterior repete 3x, todos os resultados das 3 goroutines
        // são lidos, e a main finaliza quando todos os downloads terminam
    }
    


    결과:

    concluído: http://files.com/file2.png
    concluído: http://files.com/file1.png
    concluído: http://files.com/file3.png
    


    Podemos também usar uma função anônima no lugar do downloadAndNotify , eo código completeto ficaria assim:

    package main
    
    import (
        "fmt"
        "math/rand"
        "time"
    )
    
    func download(url string) {
        r := rand.Intn(4)
        time.Sleep(time.Duration(r) * time.Second)
    }
    
    func main() {
        urls := []string{
            "http://files.com/file1.png",
            "http://files.com/file2.png",
            "http://files.com/file3.png",
        }
    
        finished := make(chan string)
    
        for _, url := range urls {
            url := url
    
            go func() {
                download(url)
                finished <- url
            }()
        }
    
        for range urls {
            url := <-finished
            fmt.Println("concluído:", url)
        }
    }
    

    좋은 웹페이지 즐겨찾기