2017-01-21 5 views
1

채널에 대한 쓰기 작업이 발생하지 않는 이상한 상황에 처해 있습니다. 채널 K 블록에 쓸 수 있지만 로그 문 fmt.Println("k ready") 인쇄되지 않습니다 이유영원히 차단 된 채널에 쓰기

start 
routine 1 
routine 2 
before 
routine 3 
x= 0 
after 
before 

가 궁금 : 여기

package main 

import (
    "fmt" 
    "time" 
) 

func main() { 
    c := make(chan int) 
    s := make(chan bool) 
    k := make(chan bool) 
    fmt.Println("start") 
    go func() { 
    fmt.Println("routine 1") 
     s <- true 
    }() 
    go func() { 
    fmt.Println("routine 2") 
     for { 
      select { 
      case <-s : 
       for i := 0; i < 3; i++ { 
        fmt.Println("before") 
        c <- i 
        fmt.Println("after") 
       }  
      case <- k : 
       fmt.Println("k ready") 
       break 
      } 
     } 
    }() 

    go func() { 
     fmt.Println("routine 3") 
     for { 
      select { 
       case x := <- c : 
       fmt.Println("x=", x) 
       k <- true 
       fmt.Println("k done") 

      } 
     } 
    }() 

    time.Sleep(1000 * time.Millisecond) 
} 

그리고

이 출력됩니다. 여기

내가 무슨 생각입니다 :

  • 일상적인 이동 1가 사실 기록 채널의
  • 2가 0 채널 c와 대기 버퍼 크기가 0이기 때문에, 그것은 할 수 없습니다를 기록 일상적인 이동 누군가가 채널 c를 읽지 않는 한 '1'을 쓰십시오.
  • 루틴 3이 화면에 나타나면 채널 c를 읽습니다 (이제 루틴 2가 다시 실행됩니다). 가 루틴 2 이력서로 다시 쓸 수 있습니다.) x의 값을 인쇄합니다. 지금은 채널 K에게 쓸 수 있어야하지만

    다음의 경우 2 실행해야 goroutine 및 인쇄의 "준비 K"채널 K에 쓸 수 있어야 날에 따르면

을 발생하지 않습니다

채널에 글을 왜 차단했는지 설명 할 수 있습니까? 수정 사항으로 채널 C의 버퍼 크기를 늘릴 수 있음을 알고 모든 것을 인쇄 할 수 있지만이 문제를 해결하는 데 관심이 없습니다. 대신이 시나리오를 이해하고 싶습니다.

좋은 blog 위의 경우를 이해합니다.

+0

링크는 [여기]입니다 (https://play.golang.org/p/3YL2eoTVn1) –

답변

1

교착 상태에 있습니다.

  • goroutine 한 후
  • goroutine 2 s로부터 판독 종료 s에 기록하고 c로부터 판독하고, k에 기록
  • goroutine 3 c에 기록하고,이 블록 때문에 아무것도 k로부터 판독되지 왜냐하면 goroutine 2는 위의 k에 대한 쓰기에서 차단되기 때문입니다. c 당신이 말하는 것과는 달리

에서 읽기되지 goroutine 3 여전히 따라서 k에 쓰기를 시도하고있는 그대로를 차단

  • goroutine이 다시 c에 기록, 당신은 하나의 버퍼 크기가없는 버퍼 크기가 0 (버퍼되지 않은 채널)이므로 읽기가 될 때까지 쓰기가 차단됩니다. 이것은 아마 당신의 오해의 원인 일 것입니다. 당 language specification :

    새로운 초기화 채널 값은 상기 채널 타입 및 인수로 선택적 용량 얻어 내장 함수 make 사용하여 제조 될 수있다 :에

    make(chan int, 100) 
    

    용량을 요소 수, 채널의 버퍼 크기를 설정합니다.용량이 0이거나 없으면 채널이 버퍼링되지 않고 발신자와 수신자 모두 준비가되었을 때만 통신이 성공합니다. 그렇지 않으면 채널이 버퍼링되고 버퍼가 가득 차거나 (전송하는) 비어 있지 않은지 (수신) 차단하지 않고 통신이 성공합니다. 무응답 채널은 결코 통신 준비가되지 않습니다. 위의 코드에

  • +0

    답장을 @abligh 감사하지만, 거기에 약간의 오타가 있거나 내가 답을 오해 것 같다. 포인트 # 2 : 채널 k에 쓰기가 반복 루틴에서 발생합니다. 또한 goroutine 3이 실행되지 않습니다. –

    +0

    그리고 당신이 언급 한 버퍼 크기 개념을 이해하지만, 나는 틀린 크기 대신 0을 말했고, 나는 [여기] (https://blog.golang.org/pipelines)를 읽었다. 나를 고쳐 주셔서 감사합니다. –

    +0

    @sheikhsabeer 나는 교착 상태 설명을 고정시켰다. – abligh