Golang - Trabalhando com Canais, um passo além do básico.

우마 브레베 히스토리아...



Estava eu ​​ajudando um colega com uma tarefa envolvendo tarefas assíncronas com golang. "Qual a melhor forma de fazer "x"coisa?". Nesse momento me vi diante de umavasidão de possibilidades de resolver aquele problema. 만족감을 느끼기 위해 무엇을 설명해야 합니까?

아이디어 컴파일 솔루션



Havia lido tempos atrás essa solução que o autor também não atribuía a si, novidade na programação (só que não!). O artigo era o seguinte MULTIPLEXING CHANNELS IN GO , aconselho que leiam se quiserem aprofundar em alguns outros tópicos como canais.

Seguir apresentarei de forma bem direta a ideia de multiplexação.

자만심:



Estamos falando da possibilidade de agregar um conjunto de canais à um único canal. Dessa forma podemos convergir os dados à um único ponto que será a retomada da sincronicidade do nosso código.

Um multiplexador (abreviação: MUX), por vezes denominado pelos anglicismos multiplexer ou multiplex, é um dispositivo que seleciona as informações de duas ou mais fontes de dados num único canal. São utilizados em situações onde o custo de implementação de canais separados para cada fonte de dados é maior que o custo e a inconveniência de utilizar as funções de multiplexação/demultiplexação. - Wikipedia. Repare nas imagens.









Vamos ao código



Seguiremos os seguintes passos:
  • Criaremos uma função de espalhamento/divergência responsável por distribuir as Tasks para vários Workers.
  • Criaremos a função do Worker que será responsável por executar a tarefa e encaminhar os resultados para o canal multiplexação (Result)
  • Criaremos a Função de agregação responsável por receber os resultados e retornar ao fluxo síncrono da execução.

  • seguintes premissas로 간주하십시오:

    // Tipo gerado para cada task poderíamos ter uma struct aqui
    type Task int
    
    // Tipo gerado para cada result poderíamos ter uma struct aqui
    type Result int
    
    // Função que representa um tempo de execução qualquer 
    // para finalização da tarefa do worker
    func asyncSimulation(t Task) int {
        time.Sleep(1 * time.Second)
        return (int(t) * int(t))
    }
    


    0 - Nossa Função 메인:




    func main() {
            // Trabalharemos com 10 tasks para serem completadas
        tasks := taskGenerator(1, 10)
        results := make(chan Result)
            // Esse wait group servirá para controlar o fechamento
            // do canal de result e evitar deadlocks 
        wg := &sync.WaitGroup{}
    
            // 5 workers serão utilizados nesse exemplo
        for i := 0; i < 5; i++ {
            wg.Add(1)
            worker(tasks, results, wg)
        }
    
            // Verificamos o momento que todos os workers 
            // terminarem de trabalhar
        verifyEnd(results, wg)
    
            // Recebemos todos os resultados no canal result
            // e imprimimos á medida que são resolvidos
        resultAggregator(results)
    }
    


    1 - 에스팔하멘토의 재미:



    Essa é a função responsável por alimentar o canal de task com as task que serão executadas.
    버퍼가 교착 상태에 빠지기 전에 Numa Goroutine에 귀속되는 데 필요한 채널을 결정하는 이유는 무엇입니까?

    func taskGenerator(start int, end int) <-chan Task {
        tasks := make(chan Task)
    
        go func() {
            for i := start; i < end; i++ {
                tasks <- Task(i)
            }
    
            close(tasks)
        }()
    
        return tasks
    }
    


    2 - Trabalhando com mais de um Worker:



    Para trabalharmos com mais de um worker precisamos também gerenciar o fechamento do canal de results, para isso definimos um wait group para os workers

    func worker(tasks <-chan Task, result chan<- Result, wg *sync.WaitGroup) {
    
        go func() {
            for task := range tasks {
                result <- Result(asyncSimulation(task))
            }
            wg.Done()
        }()
    }
    
    func verifyEnd(results chan<- Result, wg *sync.WaitGroup) {
        go func() {
            wg.Wait()
            close(results)
        }()
    }
    


    3 - A função de agregação:



    Utilizamos essa função para receber todos os dados repassados ​​para o canal de results e posteriormente somamos e mostramos eles na tela

    func resultAggregator(res <-chan Result) {
        sum := 0
        totalResults := 0
    
        for res := range res {
            fmt.Printf("received result %v\n", res)
            sum += int(res)
            totalResults += 1
        }
    
        fmt.Printf("total os squares received: %d\n", totalResults)
        fmt.Printf("sum of squares: %d", sum)
    }
    


    결과 분석




    // Após 1 segundo recebemos os primeiros 5 resultados
    // tempo gasto pelos 5 workers para processar as primeiras
    // 5 tasks
    received result 16
    received result 9
    received result 4
    received result 0
    received result 1
    // Após mais 1 segundo recebemos os próximos 5 resultados
    // tempo gasto pelos 5 workers para processar as últimas
    // 5 tasks
    received result 36
    received result 25
    received result 49
    received result 64
    received result 81
    // impressão das demais informações do agregador
    total os squares received: 10
    sum of squares: 285
    


    응용 프로그램 확장:



    Esse conceito de multiplexação é apenas um dentre vários que podemos utilizar para garantir o trabalho de forma assíncrona para solução de diversos problemas. Sua aplicação vai desde requisições para APIs externas até execução de algoritmos custosos em segmentos menores.


    폰테스


  • GO의 멀티플렉싱 채널 - https://katcipis.github.io/blog/mux-channels-go/
  • 2017년 My Go 결의안 - https://research.swtch.com/go2017
  • 멀티플렉서 - https://pt.wikipedia.org/wiki/Multiplexador
  • 좋은 웹페이지 즐겨찾기