Go Runtime은 데이터 구조, 잠금 메커니즘, 고루틴 스케줄링 및 동기화를 통해 내부적으로 채널 작업을 처리하여 고루 스틴 간의 효율적이고 공정하며 교착 상태가없는 통신을 제공합니다.
GO의 채널은 주로 데이터 구조 'HCHAN`으로 구현되며, 버퍼, 대기 송신기 대기열 및 수신기 대기열, 동기화 프리미티브 및 채널이 닫혀 있는지 여부와 같은 메타 정보를 포함하여 채널의 상태를 캡슐화합니다. 채널이 만들어지면`hchan`의 인스턴스가 힙에 할당되며, 채널을 나타내는 값은이 구조를 가리키므로 여러 고어 라인이 참조하고 동시에 사용할 수 있습니다.
코어에서 채널은 다음으로 구성됩니다.
- 슬라이스 및`sendx`와`recvx '로 표시되는 버퍼링 된 채널의 원형 버퍼는 각각 요소를 보내고 수신 할 위치를 추적합니다. 버퍼 크기는 채널 생성시 고정되어 있으며 전송 된 요소를 저장하지만 아직 수신하지 않은 큐 역할을합니다.
-Sending (`sendq`) 및 수신 (`recvq`)에서 차단 된 고어 라틴을 관리하기위한 2 개의 FIFO 대기 대기열 (링크 된 목록). 이 대기열은``sudog '구조를 저장하는데,이 구조는 전송 값 또는 값을 수신 할 위치에 대한 포인터와 같은 채널 작업에 대한 차단 된 고 루틴 및 관련 데이터를 나타냅니다.
- 채널의 내부 구조에 대한 동시 액세스를 보호하기위한 뮤 테스 잠금 장치로 보내고 수신하는 작업이 일관성을 유지하고 동시 액세스 하에서 채널 상태를 손상시키지 않도록합니다.
채널 보내기 작업
Goroutine이 채널에 값을 보내려고 시도 할 때 (`Ch E Operation
수신 작업 (`lexity :
1. 잠금 획득 : 채널의 뮤텍스가 잠겨 있습니다.
2. 대기 발신자를 확인하십시오 :`sendq '에 대기 대기하는 발신자가있는 경우 :
- 수신기는 발신자의 'sudog'에서 직접 값을 가져옵니다.
- 발신자가 탈취되고 표시 가능합니다.
- 두 goroutines는 버퍼링없이 즉시 진행됩니다.
3. 버퍼링 된 채널에 대한 버퍼 점검 : 대기중인 경우 대기중인 경우 :
- 채널은 버퍼에 요소가 포함되어 있는지 확인합니다.
- 그렇다면 요소는 버퍼 위치`buf [recvx]`에서 복사됩니다.
-`recvx '지수가 증가하고`Qcount`가 감소됩니다.
- 잠금이 해제되고 수신기는 차단하지 않고 계속됩니다.
4. 수신기 차단 : 버퍼가 비어 있고 발신자가 대기중인 경우 :
- 수신기 Goroutine은 'sudog'로 표시됩니다.
-`recvq '에 흡입됩니다.
- 수신기는 전송 작업이 차단 해제 될 때까지 스케줄러가 주차합니다.
5. 닫힌 채널 수신 : 채널이 닫히고 버퍼가 비어있는 경우 :
- 요소 유형의 0 값을 반환합니다.
- 수신기는 수신 작업에서 반환 된 두 번째 부울에 의해 차단되지 않고 폐쇄 상태를 감지 할 수 있습니다.
6. 공정성과 질서 : 대기 수신기는 공정성을 유지하기 위해 FIFO가 해소되며, 스케줄링은 순서 제약 조건을 존중하지만 스케줄러 동작으로 인한 엄격한 타이밍 순서를 보장하지는 않습니다.
주차 및 일정 통합
채널은 Go의 Goroutine 스케줄러와 밀접하게 통합되어 있으며 세 가지 엔티티를 사용하여 Goroutine 라이프 사이클을 관리합니다.
-G (Goroutine) : 가벼운 사용자 수준 스레드.
-M (machine) : Goroutines를 실행하는 OS 스레드.
-P (프로세서) : GO 코드를 실행하는 데 필요한 런닝 가능한 고어 라틴 및 리소스의 로컬 대기열을 보유합니다.
채널 작동이 차단되면 (보내거나 수신) Goroutine :
- 대기로 표시됩니다.
- 소유`p '의 로컬 런 큐에서 제거됩니다.
- 각 채널 대기열 (`sendq` 또는`recvq`)의 'sudog'구조를 통해 연결됩니다.
- 그런 다음 스케줄러는``p '에서 실행하기 위해 달리기 쉬운 고 루틴을 선택합니다.
차단 된 작업이 완료 될 준비가되면 (예 : 상대방 전송 또는 수신이 발생 함) :
- 대기 고루 틴은 채널 대기열에서 탈취됩니다.
- 마킹 가능.
- 스케줄링을 위해 로컬 또는 글로벌 런 큐에 다시 배치됩니다.
- Goroutine은 결국 실행을 재개합니다.
이 디자인은 바쁜 대기를 피하고 기존 OS 스레드 차단에 비해 최소한의 오버 헤드로 효율적인 컨텍스트 전환을 보장합니다.
채널 클로즈 작업
채널을 닫으면 동일한 뮤트에 의해 보호되는 'hchan'에서 '닫힌'플래그가 설정됩니다. 채널을 닫으면 다음이 발생합니다.
- 모든 차단 된 발신자가 보내려고 할 때 당황합니다.
- 차단 된 모든 수신기는 나머지 버퍼 값을 수신하기 위해 FIFO 순서로 차단 해제 된 다음 0 값을 차단합니다.
- 차단하지 않고 즉시 반환 0 값을 수신합니다.
- 폐쇄 된 채널 패닉을 즉시 보내십시오.
- 닫기 작업은 또한 경주 조건을 피하기 위해 뮤텍스를 통해 채널 작업과 동기화됩니다.
내부 데이터 구조
-HCHAN : 중앙 구조물 홀딩 :
-`buf` (버퍼 배열 포인터)
-`dataqsiz` (버퍼 크기)
-`Qcount` (현재 버퍼링 된 요소 수)
-`sendx`,`recvx` (버퍼 지수)
-`sendq`,`recvq` (차단 된 발신자 및 수신기의 대기 대기)
-`닫은 깃발
- 임베디드 뮤텍스 (상태를 보호하고 다중 동시 작업을 조정하기 위해).
-Sudog : 채널 작동에서 대기 대기 대기하는 Goroutine을 나타내는 내부 런타임 구조. 보류 :
- 고 루틴에 대한 포인터.
- 보내거나받는 데이터에 대한 포인터.
- 대기 대기열의 다음`sudog '에 링크됩니다.
-Waitq : 웨이터 (``sendq`)를 나타내는 Sudog의 링크 된 목록 또는 웨이터 (`recvq`)를받습니다. FIFO 공정성 보장.
문 및 채널을 선택하십시오
Go의`select` statement는 여러 채널 작업이 동시에 경쟁하기 때문에 복잡성을 소개합니다. 런타임은 각 선택 케이스에 대해 여러 대기 대기열을 관리하고 오프라인에서 여러 채널에서 선택하면 다음과 관련이 있습니다.
- 각 사례에서 비 블로킹 작업을 시도합니다.
- 아무도 진행되지 않으면 모든 관련 대기열에서 고루 틴을 흡수합니다.
- 한 번의 작업이 진행될 수 있으면 다른 웨이터가 제거되고 Goroutine이 차단 해제됩니다.
이 선택적 대기 메커니즘은 공정성과 효율성을 유지하기 위해 런타임 스케줄러와 깊이 통합됩니다.
성능 및 동시성 고려 사항
채널 설계는 안전과 성능의 균형을 유지하기 위해 노력합니다.
- Mutex 잠금 : 일관성을 보장하지만 매우 높은 경합에서 병목 현상이 될 수 있습니다. 런타임은 잠금 상태를 잠깐 고정하여 상태를 원자 적으로 업데이트합니다.
- 직접 핸드 오프 : 가능한 경우 버퍼 오버 헤드를 피하면 고어 라틴 간의 통신이 더 빠릅니다.
- 주차 및 파킹되지 않은 : OS 스레드에 비해 컨텍스트 전환 오버 헤드를 최소화합니다.
- 공정성 : 기아를 방지하기 위해 FIFO 대기열을 통해 시행됩니다.
- 캐시 및 로컬 : 버려지지 않은 Goroutines는 다른 프로세서 (`p `s)에서 재개 할 수있어 캐시 미스로 이어질 수 있습니다.
- 천둥 무리 문제 : 채널을 닫거나 방송을하면 많은 고루틴이 동시에 깨어날 수 있으며, 이는 스케줄러가 신중하게 처리해야합니다.
채널은 우아한 동시성 원시를 나타내며, 자물쇠 보호 링 버퍼를 Goroutine 스케줄링 메커니즘과 연결하여 GO 프로그램의 안전, 주문 및 효율성을 제공합니다.
GO 채널 작업의 내부는 데이터 구조, 잠금 및 런타임 스케줄러 간의 긴밀한 커플 링을 보여주고, 사용자 수준의 가벼운 스레드에 동기화를 포함시키고 무거운 OS 커널 상호 작용없이 풍부한 통신 패턴을 가능하게합니다. 이 접근법은 GO의 동시성 모델을 차별화하며 채널이 프로그래머의 관점에서 효율적이고 간단한 주요 이유입니다.