문제

환경 : OS X 10.8, Go 1.0.2

버퍼 크기 2로 채널을 만든 다음 채널을 세 번 쓰면 오류가 발생합니다.

던지기 : 모든 goroutines가 잠들었습니다 - 교착 상태!

물론 맞습니다.

하지만 Goroutines에서 채널을 4 번 이상 쓰면 괜찮습니다. 왜 작동합니까? 채널의 용량은 2인데, 왜 Goroutines가 그것을 무시하거나 용량 설정을 잊어 버리는가? 나는 읽기 채널 코드에 주석을 달므로 아무도 채널을 읽고 용량을 저장하지 않을 것입니다. 나는 또한 시간을 사용합니다. 잠 들어 모든 Goroutines가 작업을 끝내기를 기다립니다.

다음 코드를 검토하십시오 : 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)
    }*/
}

누구든지 몇 가지 히트를 주시겠습니까? 고마워요.

도움이 되었습니까?

해결책

채널이 버퍼링되면 버퍼가 가득 찼을 때까지 차단되지 않습니다. 버퍼가 가득 차면, 전송 고로 틴은 채널에 물건을 추가하려고 시도 할 때 차단됩니다.

이것은 이것이 차단 될 것임을 의미합니다.

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

그리고 이것은 할 것입니다 또한 차단하다:

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

하지만 가리키다 Goroutines와 채널 중 동시에 물건을 실행하는 것이 정확히 작동하므로 다음과 같습니다.

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

그리고 마찬가지로 :

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

예에서, 당신은 4 개의 다른 goroutines를 생성하는데, 이들은 모두 동일한 버퍼링 된 채널에 4 개의 숫자를 씁니다. 버퍼가 2 <16이므로 결국 차단됩니다.

그러나이 문제의 요점은 GO 정책이 메인 고 루틴 만 기다리십시오:

프로그램 실행은 기본 패키지를 초기화 한 다음 함수 메인을 호출하여 시작합니다. 함수가 메인을 반환하면 프로그램이 종료됩니다. 다른 (메인이 아닌) 고어 라틴이 완료되기를 기다리지 않습니다.

이것은 첫 번째 예에서 기본 Goroutine은 라인에 도달했을 때 차단되었습니다 c <- 3. 다른 Goroutine이 잠재적으로 차단 해제 할 수있는 일을 할 수 없었기 때문에 런타임은 프로그램이 교착 상태가되어 오류를보고했음을 감지했습니다.

그러나 두 번째 예에서는 산란 Goroutines 블록이 차단되는 반면, 메인은 실행의 끝에 도달 할 때까지 조용히 계속됩니다.

다른 팁

좋은 대답을했습니다. 유용하다고 생각한 추가 팁을 추가하고 싶습니다.

고어 라틴을 사용하는 법을 배울 때는 Zero-Buffered 채널을 사용하여 시작하십시오. 이렇게하면 실수를 할 때 즉시 교착 상태를 얻을 수 있습니다. 교착 상태가 아닌 코드를 작성하는 방법을 배워야합니다. 이는 클라이언트 서버 관계에서 주기적 종속성을 갖지 않는 것과 같은 트릭을 배우는 것을 의미합니다 (Goroutine이 클라이언트 또는 서버로 작성되었다고 가정).

버퍼링이없는 네트워크에 대한 추론은 더 간단하지만 처음에는 분명하지 않을 수 있습니다.

버퍼링은 정말 유용하지만 성능을 향상시키는 수단으로 간주되어야합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top