> 백엔드 개발 > Golang > Go의 `select` 문에서 연결된 채널 작업이 어떻게 교착 상태 및 데이터 손실로 이어질 수 있나요?

Go의 `select` 문에서 연결된 채널 작업이 어떻게 교착 상태 및 데이터 손실로 이어질 수 있나요?

Linda Hamilton
풀어 주다: 2024-12-01 22:04:13
원래의
740명이 탐색했습니다.

How Can Chained Channel Operations in Go's `select` Statement Lead to Deadlocks and Data Loss?

단일 선택 사례에서 채널 운영 연결: 잠재적 위험 분석

Go에서 select 문은 다중화에 편리한 방법을 제공합니다. 채널. 다음 시나리오를 생각해 보십시오. 서로 다른 간격으로 메시지를 전송하는 두 개의 채널 A와 B가 있습니다. 우리는 A와 B 모두로부터 메시지를 받는 팬인 채널을 만들고 싶습니다.

아래 코드는 이를 보여줍니다.

func fanIn(input1, input2 <-chan string) <-chan string {
    ch := make(chan string)
    go func() {
        for {
            select {
                case t := <-input1:
                    ch <- t
                case t := <-input2:
                    ch <- t
            }
        }
    }()

    return ch
}
로그인 후 복사

이 코드를 실행하면 메시지를 받을 것으로 예상됩니다. 인터리브 방식으로 두 채널 모두에서 전송됩니다. 그러나 Select Case 문을 다음과 같이 수정하면 예기치 않은 동작이 발생합니다.

func fanIn(input1, input2 <-chan string) <-chan string {
    ch := make(chan string)
    go func() {
        for {
            select {
                case ch <- <-input1:
                case ch <- <-input2:
            }
        }
    }()

    return ch
}
로그인 후 복사

이 경우 일부 메시지는 올바르게 수신되지만 값이 삭제되고 결국 교착 상태가 발생합니다. 이 동작의 이유는 select의 기본 작동에 있습니다.

select에서는 하나의 채널 읽기 또는 쓰기 작업만 비차단입니다. 다른 모든 작업은 정상적으로 작동합니다. 수정된 코드에서는 두 경우 모두 비차단 채널 쓰기가 포함되어 있습니다. 이로 인해 입력 채널의 메시지가 대기열에 추가되지만 팬인 채널은 한 번에 하나만 사용할 수 있는 상황이 발생합니다.

결과적으로 팬인 시 메시지가 삭제되고 교착 상태가 발생할 수 있습니다. 채널에는 작성자가 없으며 독자는 더 많은 값을 기다리고 있습니다.

이 문제를 방지하려면 select 문에서 하나의 작업만 비차단이어야 한다는 점을 이해하는 것이 중요합니다. 단일 선택 사례에서 여러 채널 작업을 수행해야 하는 경우 다음과 같은 비차단 선택 도우미 기능 사용을 고려하세요.

func nonBlockingSelect(cases []reflect.SelectCase) (chosen int, recv interface{}, ok bool) {
    for i, c := range cases {
        if c.Dir == reflect.SelectSend && c.Chan == nil {
            continue
        }
        v, ok := reflect.Select(cases)
        return v.Index, v.Elem().Interface(), ok
    }

    return -1, nil, false
}
로그인 후 복사

그런 다음 수정된 팬인 기능을 다음과 같이 다시 작성할 수 있습니다.

func fanIn(input1, input2 <-chan string) <-chan string {
    ch := make(chan string)
    go func() {
        for {
            select {
                case c1 := <-input1:
                    nonBlockingSelect([]reflect.SelectCase{
                        {Dir: reflect.SelectSend, Chan: reflect.ValueOf(ch), Send: reflect.ValueOf(c1)},
                    })
                case c2 := <-input2:
                    nonBlockingSelect([]reflect.SelectCase{
                        {Dir: reflect.SelectSend, Chan: reflect.ValueOf(ch), Send: reflect.ValueOf(c2)},
                    })
            }
        }
    }()

    return ch
}
로그인 후 복사

비차단 선택 도우미를 사용하면 하나의 채널 작업만 비차단으로 보장되어 값 삭제 문제를 방지하고 교착상태.

위 내용은 Go의 `select` 문에서 연결된 채널 작업이 어떻게 교착 상태 및 데이터 손실로 이어질 수 있나요?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
저자별 최신 기사
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿