G, M, P로 구성
- g - goroutine
- m - thread
- p - context
Go의 스케쥴러는 계속해서 멈추지 않고 스케쥴링을 할 수 있도록 syscall이 발생한 고루틴을 다른 스레드로 넘겨(hand off) 모든 고루틴이 정상적으로 작동할 수 있도록 보장
syscall이 발생했을 때 (blocking)
이후에 syscall 처리가 끝난 고루틴은 잠시 넘겼던 P(context)를 다시 찾아와서 붙게 되거나 global runqueues 에 들어감
Go의 스케쥴러는 syscall이 발생한 고루틴을 독립적으로 처리하도록 하면서 나머지 context는 다른 스레드(위 이미지에서 M1)로 넘김
실행중인 스레드가 blocking 되었을 때 다른 스레드로 현재 상태(state)를 그대로 넘겨 지속적으로 처리를 할 수 있도록 보장하기 위해 M에 P(context)가 붙는다
P(context)가 구현되었고 이는 GOMAXPROCS값이 1이더라도 Go가 멀티스레드로 동작하는 이유입니다
과거 Go에는 global runqueues가 있었지만 lock-release 문제로 P마다 own runqueues를 할당하는 방식으로 변경
고루틴의 CS는 다음 시점에서 이루어짐
- unbuffered 채널에 접근할 때(읽거나 쓸 때)
- 시스템 I/O가 발생했을 때
- 메모리가 할당되었을 때
time.Sleep()
코드 실행(python asyncio에서asyncio.sleep()
을 이용해 yield하는 것과 유사합니다)
runtime.Gosched()
코드 실행