>  기사  >  백엔드 개발  >  Go의 'select' 케이스에서 연결된 채널 작업이 교착 상태를 일으키는 이유는 무엇입니까?

Go의 'select' 케이스에서 연결된 채널 작업이 교착 상태를 일으키는 이유는 무엇입니까?

Linda Hamilton
Linda Hamilton원래의
2024-11-25 05:48:10957검색

Why Do Chained Channel Operations in Go's `select` Case Cause Deadlocks?

단일 선택 사례의 연결된 채널 작업: 동작 디코딩

동시 및 비동기 프로그램 설계를 추구하면서 Go의 선택 구성은 다음을 제공합니다. 채널을 멀티플렉싱하기 위한 강력한 도구입니다. 그러나 단일 선택 사례 내에서 여러 작업을 결합할 때 예상치 못한 결과가 발생하는 경우가 많습니다.

다음 시나리오를 고려해 보세요. 두 채널 A와 B가 서로 다른 시간 간격(A의 경우 10밀리초, 채널의 경우 1초)으로 메시지를 보냅니다. 비). 우리는 두 채널을 모두 듣고 수신된 값을 팬인 채널로 전달하기 위해 select를 사용합니다.

func main() {
    ch := fanIn(talk("A", 10), talk("B", 1000))

    for i := 0; i < 10; i++ {
        fmt.Printf("%q\n", <-ch)
    }
    fmt.Printf("Done\n")
}

예상 결과는 다음과 같습니다.

"A 0"
"B 0"
"A 1"
"A 2"
"A 3"
"A 4"
"B 1"
"B 2"
"B 3"
"B 4"
Done

그러나 select를 수정하면 연결된 채널 운영을 사용하는 경우:

select {
    case ch <- <-input1:
    case ch <- <-input2:
}

우리는 특이한 현상을 관찰했습니다. 동작:

"B 0"
"A 1"
"B 2"
"A 3"
"A 4"
fatal error: all goroutines are asleep - deadlock!

비하인드 스토리

이 동작을 이해하는 열쇠는 특정 사례 내 채널 운영의 비차단 특성에 있습니다. 일반적인 선택 사례에서는 하나의 채널 작업(읽기 또는 쓰기)만 비차단이 될 수 있습니다.

체인 채널 작업을 사용하면 단일 사례 내에서 여러 채널 작업을 효과적으로 시도하는 것입니다. 첫 번째 작업은 항상 차단되고 후속 작업은 비차단입니다.

수정된 코드에서 첫 번째 작업은 input1에서 값을 수신하는 것을 차단합니다. 값을 받은 후 ch 채널에 비차단 쓰기를 시도합니다. 그러나 ch 채널의 수신자가 값을 받아들일 준비가 되어 있지 않으면 쓰기 작업이 실패합니다.

연쇄 반응

실패한 쓰기 작업은 실패합니다. 선택 사례를 중지합니다. 대신, 현재 유일하게 실행 가능한 사례인 두 번째 사례로 이동합니다. 이로 인해 잠재적인 교착 상태 시나리오가 발생합니다.

시간이 지남에 따라 두 채널 모두에서 여러 값이 수신되지만 쓰기 실패로 인해 팬인 채널로 전달되지 않습니다. 결과적으로 팬인 채널은 결국 비어버리고 더 이상 값을 받을 수 없어 교착상태에 빠지게 됩니다.

문제 해결

이 문제를 방지하려면 선택 사례 내의 채널 작업이 순차적으로 실행되도록 하는 것이 중요합니다. 이는 임시 변수를 사용하여 수신된 값을 저장한 다음 Select Case 외부에서 별도의 문으로 쓰기 작업을 실행함으로써 달성할 수 있습니다.

var msg string
select {
    case msg = <-input1:
    case msg = <-input2:
}

ch <- msg

위 내용은 Go의 'select' 케이스에서 연결된 채널 작업이 교착 상태를 일으키는 이유는 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.