심층 Golang 채널: 구현 원칙 및 성능 최적화 제안
Golang의 채널은 CSP 동시성 모델의 핵심 구성 요소이자 Goroutine 간의 통신을 위한 브리지입니다. 채널은 Golang에서 자주 사용되며 내부 구현 원칙을 깊이 이해하는 것이 중요합니다. 이 기사에서는 Go 1.13 소스 코드를 기반으로 Channel의 기본 구현을 분석합니다.
채널 기본 사용법
채널 구현을 공식적으로 분석하기 전에 기본 사용법을 검토해 보겠습니다.
package main import "fmt" func main() { c := make(chan int) go func() { c <- 1 // 发送操作 }() x := <-c // 接收操作 fmt.Println(x) }
이 코드는 채널의 두 가지 기본 작업을 보여줍니다.
- 보내기 작업:
c
- 수신 작업:
x :=
채널은 버퍼링된 채널과 버퍼링되지 않은 채널로 구분됩니다. 위의 코드는 버퍼링되지 않은 채널을 사용합니다. 버퍼링되지 않은 채널에서 다른 고루틴이 현재 데이터를 수신하고 있지 않으면 발신자는 send 문에서 차단됩니다.
채널을 초기화할 때 버퍼 크기를 지정할 수 있습니다. 예를 들어 make(chan int, 2)
에서는 버퍼 크기를 2로 지정합니다. 버퍼가 가득 차기 전에 송신자는 수신자가 준비될 때까지 기다리지 않고 차단하지 않고 데이터를 보낼 수 있습니다. 그러나 버퍼가 가득 차면 발신자는 여전히 차단됩니다.
채널 기본 구현 기능
채널 소스 코드를 살펴보기 전에 Golang에서 채널의 구체적인 구현 위치를 찾아야 합니다. 채널을 사용하면 runtime.makechan
, runtime.chansend
, runtime.chanrecv
등의 기본 함수가 실제로 호출됩니다.
go tool compile -N -l -S hello.go
명령을 사용하여 코드를 어셈블리 지침으로 변환하거나 온라인 도구 컴파일러 탐색기(예: go.godbolt.org/z/3xw5Cj)를 사용할 수 있습니다. 조립 지침을 분석하여 다음을 찾을 수 있습니다.
-
make(chan int)
은runtime.makechan
기능에 해당합니다. c 은 <code>runtime.chansend
기능에 해당합니다.x := 은 <code>runtime.chanrecv
기능에 해당합니다.
이러한 기능의 구현은 Go 소스 코드의 runtime/chan.go
파일에 있습니다.
채널 구조
make(chan int)
은 컴파일러에 의해 runtime.makechan
함수로 변환되며 해당 함수 서명은 다음과 같습니다.
func makechan(t *chantype, size int) *hchan
그 중 t *chantype
은 채널 요소 유형이고, size int
은 사용자가 지정한 버퍼 크기(지정하지 않은 경우 0)이며 반환 값은 *hchan
입니다. hchan
은 Golang의 Channel 내부 구현 구조로 다음과 같이 정의됩니다.
type hchan struct { qcount uint // 缓冲区中已放入元素的数量 dataqsiz uint // 用户构造Channel时指定的缓冲区大小 buf unsafe.Pointer // 缓冲区 elemsize uint16 // 缓冲区中每个元素的大小 closed uint32 // Channel是否关闭,==0表示未关闭 elemtype *_type // Channel元素的类型信息 sendx uint // 缓冲区中发送元素的索引位置(发送索引) recvx uint // 缓冲区中接收元素的索引位置(接收索引) recvq waitq // 等待接收的Goroutine列表 sendq waitq // 等待发送的Goroutine列表 lock mutex }
hchan
의 속성은 대략 세 가지 범주로 나뉩니다.
-
버퍼 관련 속성:
buf
,dataqsiz
,qcount
등 Channel의 버퍼 크기가 0이 아닌 경우, 수신할 데이터를 저장하는 버퍼로 사용되며, 링 버퍼를 이용하여 구현된다. -
대기 대기열 관련 속성:
recvq
에는 데이터 수신을 기다리는 고루틴이 포함되고,sendq
에는 데이터 전송을 기다리는 고루틴이 포함됩니다.waitq
이중 연결 리스트를 사용하여 구현되었습니다. -
기타 속성:
lock
,elemtype
,closed
등
makechan
함수는 주로 일부 합법성 검사와 버퍼 및 hchan
과 같은 속성의 메모리 할당을 수행하는데, 이에 대해서는 여기서 자세히 설명하지 않습니다.
hchan
속성을 간단히 분석해 보면 버퍼와 대기 큐라는 두 가지 중요한 구성 요소가 있음을 알 수 있습니다. hchan
의 모든 동작과 구현은 이 두 구성 요소를 중심으로 이루어집니다.
채널 데이터 전송
채널의 전송 및 수신 프로세스는 매우 유사합니다. 먼저 채널(예: c )의 전송 프로세스를 분석합니다.
가 채널에 데이터를 보내려고 할 때 recvq
대기열이 비어 있지 않으면 데이터 수신을 기다리고 있는 고루틴이 recvq
헤더에서 제거되고 데이터가 고루틴으로 직접 전송됩니다. 코드는 다음과 같습니다.
package main import "fmt" func main() { c := make(chan int) go func() { c <- 1 // 发送操作 }() x := <-c // 接收操作 fmt.Println(x) }
recvq
데이터 수신을 기다리는 고루틴이 포함되어 있습니다. 고루틴이 수신 작업(예: x := )을 사용할 때 <code>sendq
가 이때 비어 있지 않으면 sendq
에서 고루틴을 가져오고 데이터가 해당 고루틴으로 전송됩니다.
recvq
이 비어 있으면 현재 데이터 수신을 기다리고 있는 고루틴이 없으며 채널이 데이터를 버퍼에 넣으려고 시도한다는 의미입니다.
func makechan(t *chantype, size int) *hchan
이 코드의 기능은 매우 간단합니다. 데이터를 버퍼에 넣는 것입니다. 이 프로세스에는 링 버퍼의 작업이 포함되며, dataqsiz
은 사용자가 지정한 버퍼 크기를 나타냅니다(지정하지 않은 경우 기본값은 0).
버퍼되지 않은 채널을 사용하거나 버퍼가 가득 찬 경우(c.qcount == c.dataqsiz
), 전송할 데이터와 현재 고루틴은 sudog
객체로 패키징되어 sendq
에 배치되고, 현재 고루틴은 대기 상태로 설정됩니다:
type hchan struct { qcount uint // 缓冲区中已放入元素的数量 dataqsiz uint // 用户构造Channel时指定的缓冲区大小 buf unsafe.Pointer // 缓冲区 elemsize uint16 // 缓冲区中每个元素的大小 closed uint32 // Channel是否关闭,==0表示未关闭 elemtype *_type // Channel元素的类型信息 sendx uint // 缓冲区中发送元素的索引位置(发送索引) recvx uint // 缓冲区中接收元素的索引位置(接收索引) recvq waitq // 等待接收的Goroutine列表 sendq waitq // 等待发送的Goroutine列表 lock mutex }
goparkunlock
은 입력 뮤텍스를 잠금 해제하고 현재 고루틴을 일시 중지하여 대기 상태로 설정합니다. gopark
과 goready
은 쌍으로 나타나며 상호 연산입니다.
사용자 입장에서는 gopark
호출 후 데이터 전송을 위한 코드문이 차단됩니다.
채널 데이터 수신
채널의 수신 과정은 기본적으로 전송 과정과 유사하므로 여기서는 자세히 설명하지 않겠습니다. 수신 과정에서 발생하는 버퍼 관련 동작에 대해서는 뒤에서 자세히 설명한다.
runtime.mutex
을 사용하면 채널의 전체 송수신 과정이 잠겨 있으므로 주의해야 합니다. runtime.mutex
은 런타임 관련 소스 코드에서 일반적으로 사용되는 경량 잠금입니다. 전체 프로세스가 가장 효율적인 잠금 없는 솔루션은 아닙니다. Golang의 잠금 없는 채널에 관한 문제가 있습니다: go/issues#8899.
채널 링 버퍼 구현
채널은 링 버퍼를 사용하여 작성된 데이터를 캐시합니다. 링 버퍼에는 많은 장점이 있으며 고정 길이 FIFO 대기열을 구현하는 데 이상적입니다.
채널의 링 버퍼 구현은 다음과 같습니다.
hchan
에는 버퍼 관련 변수가 두 개 있는데, recvx
과 sendx
입니다. sendx
은 버퍼에 쓰기 가능한 인덱스를 나타내고, recvx
는 버퍼에 읽기 가능한 인덱스를 나타냅니다. recvx
과 sendx
사이의 요소는 정상적으로 버퍼에 담긴 데이터를 나타냅니다.

buf[recvx]
을 사용하여 큐의 첫 번째 요소를 직접 읽을 수 있고, buf[sendx] = x
을 사용하여 해당 요소를 큐의 끝에 넣을 수 있습니다.
버퍼 쓰기
버퍼가 가득 차지 않은 경우, 버퍼에 데이터를 넣는 동작은 다음과 같습니다.
package main import "fmt" func main() { c := make(chan int) go func() { c <- 1 // 发送操作 }() x := <-c // 接收操作 fmt.Println(x) }
chanbuf(c, c.sendx)
은 c.buf[c.sendx]
과 동일합니다. 위의 과정은 매우 간단합니다. 데이터를 버퍼 위치sendx
에 복사하기만 하면 됩니다.
그런 다음 sendx
을 다음 위치로 이동하세요. sendx
이 마지막 위치에 도달하면 0으로 설정되는데, 이는 일반적인 end-to-end 접근 방식입니다.
버퍼 읽기
버퍼가 가득 차지 않으면 sendq
도 비어 있어야 합니다(왜냐하면 버퍼가 가득 차지 않으면 데이터를 보내는 고루틴이 대기열에 들어가지 않고 데이터를 직접 버퍼에 넣기 때문입니다). 이때 채널 chanrecv
의 읽기 로직은 비교적 간단합니다. 버퍼에서 직접 데이터를 읽을 수도 있으며, 이는 기본적으로 위의 버퍼 쓰기와 동일합니다. recvx
에 대기 중인 고루틴이 있으면 이때 버퍼가 가득 차 있어야 합니다. 이때 채널의 읽기 로직은 다음과 같습니다. sendq
func makechan(t *chantype, size int) *hchan
은 데이터를 받는 변수에 해당하는 주소입니다(예를 들어 ep
에서 x := 은 <code>ep
의 주소입니다). x
은 sg
에서 가져온 첫 번째 sendq
를 나타냅니다. 코드에서: sudog
- 은 버퍼에서 현재 읽을 수 있는 요소를 수신 변수의 주소에 복사하는 것을 의미합니다.
typedmemmove(c.elemtype, ep, qp)
- 은
typedmemmove(c.elemtype, qp, sg.elem)
에서 고루틴이 전송하기를 기다리는 데이터를 버퍼에 복사하는 것을 의미합니다.sendq
은 나중에 실행되기 때문에 대기열 끝에recv
에 데이터를 배치하는 것과 같습니다.sendq
의 요소를 대기열 끝에 복사하여 FIFO(선입선출)를 구현합니다. . sendq
요약
채널은 Golang에서 가장 일반적으로 사용되는 기능 중 하나입니다. 소스 코드를 이해하면 채널을 더 잘 사용하고 이해하는 데 도움이 됩니다. 동시에 지나치게 미신을 믿지 말고 채널의 성능에 의존하지 마십시오. 현재 채널의 디자인에는 여전히 최적화할 여지가 많습니다.
최적화 제안:
- 성능을 향상하려면 더 가벼운 잠금 메커니즘이나 잠금 없는 방식을 사용하세요.
- 버퍼 관리를 최적화하고 메모리 할당 및 복사 작업을 줄입니다.
Leapcell: Golang 웹 애플리케이션을 위한 최고의 서버리스 플랫폼

마지막으로 Go 서비스 배포에 매우 적합한 플랫폼을 추천합니다: Leapcell
- 다국어 지원: JavaScript, Python, Go 또는 Rust 개발을 지원합니다.
- 무제한 프로젝트를 무료로 배포: 사용한 만큼만 비용을 지불하고 요청이나 수수료가 없습니다.
- 매우 비용 효율적: 사용한 만큼만 지불하고 유휴 수수료가 없습니다. 예를 들어 $25는 평균 응답 시간이 60밀리초인 694만 개의 요청을 지원합니다.
- 원활한 개발자 환경: 손쉬운 설정을 위한 직관적인 UI, 실행 가능한 통찰력을 위한 완전 자동화된 CI/CD 파이프라인 및 GitOps 통합.
- 쉬운 확장성 및 고성능: 자동으로 확장하여 높은 동시성을 쉽게 처리하고 운영 오버헤드가 없으며 구축에 집중합니다.

자세한 내용은 설명서를 확인하세요!
Leapcell 트위터: https://www.php.cn/link/7884effb9452a6d7a7a79499ef854afd
위 내용은 Go 채널 잠금 해제: 작동 방식의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

golangisidealforbuildingscalablesystemsdueToitsefficiencyandconcurrency

Golang은 동시성에서 C보다 낫고 C는 원시 속도에서 Golang보다 낫습니다. 1) Golang은 Goroutine 및 Channel을 통해 효율적인 동시성을 달성하며, 이는 많은 동시 작업을 처리하는 데 적합합니다. 2) C 컴파일러 최적화 및 표준 라이브러리를 통해 하드웨어에 가까운 고성능을 제공하며 극도의 최적화가 필요한 애플리케이션에 적합합니다.

Golang을 선택하는 이유는 다음과 같습니다. 1) 높은 동시성 성능, 2) 정적 유형 시스템, 3) 쓰레기 수집 메커니즘, 4) 풍부한 표준 라이브러리 및 생태계는 효율적이고 신뢰할 수있는 소프트웨어를 개발하기에 이상적인 선택입니다.

Golang은 빠른 개발 및 동시 시나리오에 적합하며 C는 극도의 성능 및 저수준 제어가 필요한 시나리오에 적합합니다. 1) Golang은 쓰레기 수집 및 동시성 메커니즘을 통해 성능을 향상시키고, 고전성 웹 서비스 개발에 적합합니다. 2) C는 수동 메모리 관리 및 컴파일러 최적화를 통해 궁극적 인 성능을 달성하며 임베디드 시스템 개발에 적합합니다.

Golang은 컴파일 시간과 동시 처리에서 더 나은 성능을 발휘하는 반면 C는 달리기 속도 및 메모리 관리에서 더 많은 장점을 가지고 있습니다. 1. 골랑은 빠른 컴파일 속도를 가지고 있으며 빠른 개발에 적합합니다. 2.C는 빠르게 실행되며 성능 크리티컬 애플리케이션에 적합합니다. 3. Golang은 동시 처리에 간단하고 효율적이며 동시 프로그래밍에 적합합니다. 4.C 수동 메모리 관리는 더 높은 성능을 제공하지만 개발 복잡성을 증가시킵니다.

웹 서비스 및 시스템 프로그래밍에서 Golang의 응용 프로그램은 주로 단순성, 효율성 및 동시성에 반영됩니다. 1) 웹 서비스에서 Golang은 강력한 HTTP 라이브러리 및 동시 처리 기능을 통해 고성능 웹 애플리케이션 및 API의 생성을 지원합니다. 2) 시스템 프로그래밍에서 Golang은 운영 체제 개발 및 임베디드 시스템에 적합하기 위해 하드웨어에 가까운 기능 및 C 언어와 호환성을 사용합니다.

Golang과 C는 성능 비교에서 고유 한 장점과 단점이 있습니다. 1. Golang은 높은 동시성과 빠른 발전에 적합하지만 쓰레기 수집은 성능에 영향을 줄 수 있습니다. 2.C는 더 높은 성능과 하드웨어 제어를 제공하지만 개발 복잡성이 높습니다. 선택할 때는 프로젝트 요구 사항과 팀 기술을 포괄적 인 방식으로 고려해야합니다.

Golang은 고성능 및 동시 프로그래밍 시나리오에 적합하지만 Python은 빠른 개발 및 데이터 처리에 적합합니다. 1. Golang은 단순성과 효율성을 강조하며 백엔드 서비스 및 마이크로 서비스에 적합합니다. 2. Python은 간결한 구문 및 풍부한 라이브러리로 유명하며 데이터 과학 및 기계 학습에 적합합니다.


핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

Video Face Swap
완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

인기 기사

뜨거운 도구

PhpStorm 맥 버전
최신(2018.2.1) 전문 PHP 통합 개발 도구

맨티스BT
Mantis는 제품 결함 추적을 돕기 위해 설계된 배포하기 쉬운 웹 기반 결함 추적 도구입니다. PHP, MySQL 및 웹 서버가 필요합니다. 데모 및 호스팅 서비스를 확인해 보세요.

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

MinGW - Windows용 미니멀리스트 GNU
이 프로젝트는 osdn.net/projects/mingw로 마이그레이션되는 중입니다. 계속해서 그곳에서 우리를 팔로우할 수 있습니다. MinGW: GCC(GNU Compiler Collection)의 기본 Windows 포트로, 기본 Windows 애플리케이션을 구축하기 위한 무료 배포 가능 가져오기 라이브러리 및 헤더 파일로 C99 기능을 지원하는 MSVC 런타임에 대한 확장이 포함되어 있습니다. 모든 MinGW 소프트웨어는 64비트 Windows 플랫폼에서 실행될 수 있습니다.

WebStorm Mac 버전
유용한 JavaScript 개발 도구
