고루틴은 Go 디자인의 초석으로, 동시 프로그래밍을 위한 강력한 메커니즘을 제공합니다. 경량 코루틴으로서 병렬 작업 실행을 단순화합니다. 고루틴 실행은 간단합니다. 함수 호출 앞에 go
키워드를 붙여 비동기 실행을 시작하기만 하면 됩니다. 고루틴이 완료될 때까지 기다리지 않고 메인 프로그램이 계속됩니다.
<code class="language-go">go func() { // Launch a goroutine using the 'go' keyword // ... code to be executed concurrently ... }()</code>
동시성: 단일 CPU에서 동시에 여러 작업을 관리하는 능력입니다. CPU는 작업 간을 빠르게 전환하여 병렬 실행이라는 착각을 불러일으킵니다. 미시적으로는 순차적이지만 거시적으로는 동시적으로 나타납니다.
병렬성: 여러 CPU에서 여러 작업을 동시에 실행하여 CPU 리소스 경합을 제거합니다.
프로세스: 자체 리소스(메모리, 파일 등)를 갖춘 독립형 실행 환경입니다. 프로세스 간 전환은 리소스 집약적이며 커널 수준 개입이 필요합니다.
스레드: 프로세스 내의 경량 실행 단위로, 프로세스의 리소스를 공유합니다. 스레드 전환은 프로세스 전환보다 오버헤드가 적습니다.
코루틴은 자체 레지스터 컨텍스트와 스택을 유지합니다. 코루틴 간 전환에는 이 상태를 저장하고 복원하여 중단된 부분부터 실행을 재개할 수 있는 작업이 포함됩니다. 프로세스 및 스레드와 달리 코루틴 관리는 운영 체제가 아닌 사용자 프로그램 내에서 처리됩니다. 고루틴은 특정 유형의 코루틴입니다.
Go의 효율적인 동시성은 GPM 스케줄링 모델에 의존합니다. M, P, G 및 Sched의 네 가지 주요 구성 요소가 관련됩니다(Sched는 다이어그램에 표시되지 않음).
M(머신): 커널 수준 스레드입니다. 고루틴은 Ms.
에서 실행됩니다.G(고루틴): 단일 고루틴입니다. 각 G에는 자체 스택, 명령어 포인터 및 기타 예약 관련 정보(예: 대기 중인 채널)가 있습니다.
P(Processor): 고루틴을 관리하고 실행하는 논리 프로세서입니다. 준비된 고루틴의 실행 대기열을 유지합니다.
Sched(Scheduler): M 및 G 대기열을 관리하고 효율적인 리소스 할당을 보장하는 중앙 스케줄러입니다.
다이어그램은 고루틴을 실행하는 프로세서(P)가 있는 두 개의 OS 스레드(M)를 보여줍니다.
GOMAXPROCS()
은 P 개수(따라서 실제 동시성 수준)를 제어합니다.
회색 G가 준비되었지만 아직 실행되지 않았습니다. P는 이 실행 대기열을 관리합니다.
고루틴을 실행하면 P의 실행 대기열에 추가됩니다.
M0이 차단되면 P는 M1으로 전환합니다(스레드 캐시에서 검색할 수 있음).
P가 작업을 빨리 완료하면 효율성을 유지하기 위해 다른 P의 작업을 훔칠 수도 있습니다.
고루틴 실행을 위한 CPU 수를 설정합니다(최근 Go 버전의 기본 설정이면 일반적으로 충분합니다).
<code class="language-go">go func() { // Launch a goroutine using the 'go' keyword // ... code to be executed concurrently ... }()</code>
<code class="language-go">num := runtime.NumCPU() // Get the number of logical CPUs runtime.GOMAXPROCS(num) // Set the maximum number of concurrently running goroutines</code>
고루틴에서 처리되지 않은 예외는 전체 프로그램을 종료할 수 있습니다. 패닉을 처리하려면 recover()
문 내에서 defer
을 사용하세요.
<code class="language-go">package main import ( "fmt" "runtime" ) func cal(a, b int) { c := a + b fmt.Printf("%d + %d = %d\n", a, b, c) } func main() { runtime.GOMAXPROCS(runtime.NumCPU()) for i := 0; i < 10; i++ { go cal(i, i+1) } //Note: The main function exits before goroutines complete in this example. See later sections for synchronization. }</code>
고루틴은 비동기적으로 실행되므로 완료되기 전에 기본 프로그램이 종료될 수 있습니다. 동기화를 위해 sync.WaitGroup
또는 채널을 사용하세요:
sync.WaitGroup
<code class="language-go">package main import ( "fmt" ) func addele(a []int, i int) { defer func() { if r := recover(); r != nil { fmt.Println("Error in addele:", r) } }() a[i] = i // Potential out-of-bounds error if i is too large fmt.Println(a) } func main() { a := make([]int, 4) for i := 0; i < 5; i++ { go addele(a, i) } // ... (add synchronization to wait for goroutines to finish) ... }</code>
<code class="language-go">package main import ( "fmt" "sync" ) func cal(a, b int, wg *sync.WaitGroup) { defer wg.Done() c := a + b fmt.Printf("%d + %d = %d\n", a, b, c) } func main() { var wg sync.WaitGroup for i := 0; i < 10; i++ { wg.Add(1) go cal(i, i+1, &wg) } wg.Wait() }</code>
채널은 고루틴 간의 통신과 데이터 공유를 용이하게 합니다. 전역 변수도 사용할 수 있지만 더 나은 동시성 제어를 위해서는 일반적으로 채널이 선호됩니다.
<code class="language-go">package main import ( "fmt" ) func cal(a, b int, ch chan bool) { c := a + b fmt.Printf("%d + %d = %d\n", a, b, c) ch <- true // Signal completion } func main() { ch := make(chan bool, 10) // Buffered channel to avoid blocking for i := 0; i < 10; i++ { go cal(i, i+1, ch) } for i := 0; i < 10; i++ { <-ch // Wait for each goroutine to finish } }</code>
Leapcell은 Go 서비스 배포에 권장되는 플랫폼입니다.
주요 기능:
문서에서 자세히 알아보세요!
Leapcell 트위터: https://www.php.cn/link/7884effb9452a6d7a7a79499ef854afd
위 내용은 Go의 동시성 디코딩: 고루틴 스케줄링의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!