Golang: Desmistificando 채널 - 버퍼링된 채널

8394 단어

버퍼링된 채널



Se você já conseguiu entender e praticar bem a parte de channels, podemos falar sobre buffered channels.

버퍼링된 채널은 채널에 저장되어 있는 모든 시나리오에서 보호할 수 있고, 보호할 수 있는 환경에서 임시 버퍼로 보호할 수 있으며, 버퍼를 사용할 수 있고 제거할 수 있습니다.

예를 들어 5에서 버퍼링된 채널에서 버퍼링된 채널은 고루틴에서 5가지 환경에서 사용됩니다.

Partir daí, enquanto o buffer estiver cheio, os próximos envios vão bloquear, da mesma forma que num channel sem buffer.

// basta passar um tamanho na hora de criar o channel
ch := make(chan string, 3)

// não vão bloquear a gourotine
ch <- "A"
ch <- "B"
ch <- "C"

// buffer cheio, novos envios vão bloquear a goroutine 
// até que surja um  espaço livre no buffer
ch <- "D"


Da mesma forma, receber de um buffered channel não vai bloquear se o buffer não estiver vazio.

Se ele estiver vazio, vai funcionar como um channel sem buffer.

ch := make(chan string, 3)

// não vão bloquear a gourotine
ch <- "A"
ch <- "B"
ch <- "C"

// não vão bloquear a goroutine
<-ch // "A"
<-ch // "B"
<-ch // "C"

// buffer vazio, vai bloquear a goroutine até um novo envio
<-ch


Usando 버퍼링된 채널 파라 제어 숫자 고루틴



Uma grande vantagem dos buffered channels é que eles passam a bloquear quando o buffer está cheio, e podemos usar isso ao nosso favor.

Nesse exemplo aqui eu tenho um programa que vai ficar criando goroutines indeterminadamente e cada goroutine faz uma requisição GET.

package main

import (
    "fmt"
    "net/http"
)

func main() {
    for {
        go func() {
            client := http.Client{}

            resp, _ := client.Get("https://www.google.com")
            resp.Body.Close()

            fmt.Println(resp.Status)
        }()
    }
}


어떤 문제는 클라이언트와 클라이언트의 HTTP sem 제한에 대한 포드 데모의 문제점으로, 무한히 기억할 수 없고 효율적으로 사용할 수 없습니다.

Esse programa vai cedo ou tarde dar um erro e vai encerrar:

"runtime error: invalid memory address or nil pointer dereference"

Stack:
    4  0x0000000000744764 in main.main.func1
        at /home/igor/Git/pessoal/got/main.go:21


Para resolver isso, vamos criar um buffered channel antes do loop:

// o tipo não importa muito, porque não estamos interessados no valor enviado
// nesse caso vou limitar para 50 goroutines fazendo requisições
limitter := make(chan bool, 50)


Toda vez antes de criar uma goroutine vamos adicionar um valor ao buffer:

for {
    limitter <- true

    go func() {
        ...
    }()
}


이제 고루틴 최종화자, vamos tirar um valor do buffer:

for {
    limitter <- true

    go func() {
        ...
        <-limitter
    }()
}


O resultado vai ser:

package main

import (
    "fmt"
    "net/http"
)

func main() {
    finished := make(chan bool, 50)
    for {
        finished <- true

        go func() {
            client := http.Client{}

            resp, _ := client.Get("https://www.google.com")
            resp.Body.Close()

            fmt.Println(resp.Status)
            <-finished
        }()
    }
}

좋은 웹페이지 즐겨찾기