Golang 스케줄에 대해서.
11302 단어 Go
개시하다
올해 들어 일에 골랑이라고 쓰여 있어서 스케줄을 조사해 봤습니다.투덜거려도 자료가 많지 않으니 정리해 봤다.소스 코드를 참조할 때 Go 1.9.3이 표시됩니다.나는 이해하기 쉬운 부분을 매우 중시하기 때문에 매우 간단하게 설명하였으니 양해해 주십시오.
잘못된 점이 있을 수 있으니 자세한 사람은 부드럽게 말씀해 주세요.
고로틴에 대한 기본적인 이야기입니다.
goroutine는 녹색 라인, 즉 OS의 라인을 직접 사용하지 않았다.따라서 고루틴 제작은 현지 라인을 만드는 것보다 처리 원가가 훨씬 싸다.이 고로틴을 여러 개 만들면 실행 시간이 자동으로 다중 라인으로 실행됩니다.상세한 상황은 후술하다.
그리고 메인 프로그램도 고로틴으로 관리된다.
배차 중인 등장인물
중요한 등장인물은 M, G, P 세 명이다.
goroutine는 녹색 라인, 즉 OS의 라인을 직접 사용하지 않았다.따라서 고루틴 제작은 현지 라인을 만드는 것보다 처리 원가가 훨씬 싸다.이 고로틴을 여러 개 만들면 실행 시간이 자동으로 다중 라인으로 실행됩니다.상세한 상황은 후술하다.
그리고 메인 프로그램도 고로틴으로 관리된다.
배차 중인 등장인물
중요한 등장인물은 M, G, P 세 명이다.
스케줄링의 기본 메커니즘
GOMAXPROCS 수량을 위한 M, P 그룹이 준비되어 있습니다.GOMAXPROCS가 2인 경우 대체로 다음과 같은 방식으로 수행됩니다.
그리고 한 측이 G를 모두 실행하고 한가할 때 다른 P에게서 G의 반을 빼앗는다.
이 스케줄링 알고리즘은workstealing 알고리즘이라고 한다.이workstealing 알고리즘은 CPU 반사 처리가 매우 효율적이지만 iowait 등 쓸모없이 막힌 처리와는 맞지 않는다.거기서 몇 가지 방법을 만들었어요. 지금부터 설명해 드릴게요.
상세 진입 전 준비
필요한 사전 지식을 상세히 설명하다.
필요한 사전 지식을 상세히 설명하다.
Syscall 실행 시
systcall을 사용할 때, 그systcall가 바로 되돌아오면 일반적인 처리와 거의 변화가 없습니다.
systcall을 사용하는 데 시간이 걸리는 경우(최소 20nsec 이상)에서systmon은 이를 검출하여 이 M과 G를 P에서 분리하고 다른 M과 P를 연결시켜 처리한다3.
↓
Syscall이 끝나면 먼저 한가한 P가 있으면 그것을 가져와서 처리합니다.
↓
안 되면 전 세계 대열에 추가할게요.M이 M idle list에 추가됩니다.
네트워크 처리 중
네트워크 처리는 넷폴러라고 불리는 메커니즘을 가져왔다.Go의 라이브러리에서 제공하는 네트워크 처리의 API에서 차단됩니다. 이 넷폴러는 실행할 때 비차단 처리를 합니다.이 비차단 처리는 Linux는 epoll, BSD는 kqueue 등 OS에서 제공하는 기능을 내용적으로 사용했다.
실제 구조는 네트워크의 대기 시간에 G가 M에서 분리되어 netpoller에 로그인하는 것이다.Sysmon은 Netpoller를 정기적으로 검사하여 네트워크 처리 준비가 되면 G를 글로벌 큐에 저장합니다.
이것들은 epoll을 사용하여 설치한 경우 등록 부분에서 epollctl, 획득 부분은 epollwait를 사용합니다.
G의 실행 시간
만약 M이 계속 같은 G(최소 10ms 이상)를 집행한다면 이 G에 대해 프레셔스를 하는 기능도 있다.
systmon이 10ms 이상의 G를 사용한 것을 발견했을 때, 이 G의 preempt 로고를 진짜로 설정합니다.이때 프레셔스를 진행하지 않습니다.
실제로 적용되는 것은 표시된 한쪽이다.표시된 G 호출 함수가 preempt 로고를 보았을 때 전역 대기열을 압축합니다.
receive/send channel 때.
G가 채널의receive를 기다리면 채널 1의 대기 G 목록에 초대됩니다.
다른 G가send에서 채널 1로 이동할 때 채널 1의 대기열 G 목록에서send G의 P 대기열에 저장됩니다.
Golang 소스 코드의 주법
여기까지만 하면 점심시간 행사가 끝난다.
Go 라이브러리의 소스 코드를 읽을 때 중간에 선언이 있지만 실현되지 않은 함수가 나타날 때가 있다.이것은 go:linkname가 사용된 상황과 어셈블리 언어로 정의된 상황4을 가리킨다.
goo:linkname 디렉터리의 경우 ^//go:linkname \S* importpath\.name
로 검색하면 나옵니다.예를 들어 poll. runtime_pollWait를 통해 검색^//go:linkname \S+ internal/poll\.runtime_pollWait
할 수 있다.$ grep -P -r '^//go:linkname \S+ internal/poll\.runtime_pollWait' .
./runtime/netpoll.go://go:linkname poll_runtime_pollWait internal/poll.runtime_pollWait
./runtime/netpoll.go://go:linkname poll_runtime_pollWaitCanceled internal/poll.runtime_pollWaitCanceled
즉, 실현은 바로 이것이다
네트워크 처리는 넷폴러라고 불리는 메커니즘을 가져왔다.Go의 라이브러리에서 제공하는 네트워크 처리의 API에서 차단됩니다. 이 넷폴러는 실행할 때 비차단 처리를 합니다.이 비차단 처리는 Linux는 epoll, BSD는 kqueue 등 OS에서 제공하는 기능을 내용적으로 사용했다.
실제 구조는 네트워크의 대기 시간에 G가 M에서 분리되어 netpoller에 로그인하는 것이다.Sysmon은 Netpoller를 정기적으로 검사하여 네트워크 처리 준비가 되면 G를 글로벌 큐에 저장합니다.
이것들은 epoll을 사용하여 설치한 경우 등록 부분에서 epollctl, 획득 부분은 epollwait를 사용합니다.
G의 실행 시간
만약 M이 계속 같은 G(최소 10ms 이상)를 집행한다면 이 G에 대해 프레셔스를 하는 기능도 있다.
systmon이 10ms 이상의 G를 사용한 것을 발견했을 때, 이 G의 preempt 로고를 진짜로 설정합니다.이때 프레셔스를 진행하지 않습니다.
실제로 적용되는 것은 표시된 한쪽이다.표시된 G 호출 함수가 preempt 로고를 보았을 때 전역 대기열을 압축합니다.
receive/send channel 때.
G가 채널의receive를 기다리면 채널 1의 대기 G 목록에 초대됩니다.
다른 G가send에서 채널 1로 이동할 때 채널 1의 대기열 G 목록에서send G의 P 대기열에 저장됩니다.
Golang 소스 코드의 주법
여기까지만 하면 점심시간 행사가 끝난다.
Go 라이브러리의 소스 코드를 읽을 때 중간에 선언이 있지만 실현되지 않은 함수가 나타날 때가 있다.이것은 go:linkname가 사용된 상황과 어셈블리 언어로 정의된 상황4을 가리킨다.
goo:linkname 디렉터리의 경우 ^//go:linkname \S* importpath\.name
로 검색하면 나옵니다.예를 들어 poll. runtime_pollWait를 통해 검색^//go:linkname \S+ internal/poll\.runtime_pollWait
할 수 있다.$ grep -P -r '^//go:linkname \S+ internal/poll\.runtime_pollWait' .
./runtime/netpoll.go://go:linkname poll_runtime_pollWait internal/poll.runtime_pollWait
./runtime/netpoll.go://go:linkname poll_runtime_pollWaitCanceled internal/poll.runtime_pollWaitCanceled
즉, 실현은 바로 이것이다
G가 채널의receive를 기다리면 채널 1의 대기 G 목록에 초대됩니다.
다른 G가send에서 채널 1로 이동할 때 채널 1의 대기열 G 목록에서send G의 P 대기열에 저장됩니다.
Golang 소스 코드의 주법
여기까지만 하면 점심시간 행사가 끝난다.
Go 라이브러리의 소스 코드를 읽을 때 중간에 선언이 있지만 실현되지 않은 함수가 나타날 때가 있다.이것은 go:linkname가 사용된 상황과 어셈블리 언어로 정의된 상황4을 가리킨다.
goo:linkname 디렉터리의 경우 ^//go:linkname \S* importpath\.name
로 검색하면 나옵니다.예를 들어 poll. runtime_pollWait를 통해 검색^//go:linkname \S+ internal/poll\.runtime_pollWait
할 수 있다.$ grep -P -r '^//go:linkname \S+ internal/poll\.runtime_pollWait' .
./runtime/netpoll.go://go:linkname poll_runtime_pollWait internal/poll.runtime_pollWait
./runtime/netpoll.go://go:linkname poll_runtime_pollWaitCanceled internal/poll.runtime_pollWaitCanceled
즉, 실현은 바로 이것이다
$ grep -P -r '^//go:linkname \S+ internal/poll\.runtime_pollWait' .
./runtime/netpoll.go://go:linkname poll_runtime_pollWait internal/poll.runtime_pollWait
./runtime/netpoll.go://go:linkname poll_runtime_pollWaitCanceled internal/poll.runtime_pollWaitCanceled
어셈블리 언어에 정의된 경우
^TEXT.*·Name\(
로 검색하면 (주의: Name의 앞쪽은 .
이 아니라 ·
(U+00B7) 이다.예를 들어 syscall.Syscall 그렇습니다.$ grep -P -r '^TEXT.*·Syscall\('
syscall/asm_darwin_386.s:TEXT ·Syscall(SB),NOSPLIT,$0-28
syscall/asm_darwin_amd64.s:TEXT ·Syscall(SB),NOSPLIT,$0-56
syscall/asm_darwin_arm.s:TEXT ·Syscall(SB),NOSPLIT,$0-28
syscall/asm_darwin_arm64.s:TEXT ·Syscall(SB),NOSPLIT,$0-56
syscall/asm_freebsd_arm.s:TEXT ·Syscall(SB),NOSPLIT,$0-28
syscall/asm_linux_386.s:TEXT ·Syscall(SB),NOSPLIT,$0-28
syscall/asm_linux_amd64.s:TEXT ·Syscall(SB),NOSPLIT,$0-56
syscall/asm_linux_arm.s:TEXT ·Syscall(SB),NOSPLIT,$0-28
syscall/asm_linux_arm64.s:TEXT ·Syscall(SB),NOSPLIT,$0-56
syscall/asm_linux_mips64x.s:TEXT ·Syscall(SB),NOSPLIT,$0-56
syscall/asm_linux_mipsx.s:TEXT ·Syscall(SB),NOSPLIT,$0-28
syscall/asm_linux_ppc64x.s:TEXT ·Syscall(SB),NOSPLIT,$0-56
syscall/asm_linux_s390x.s:TEXT ·Syscall(SB),NOSPLIT,$0-56
syscall/asm_nacl_386.s:TEXT ·Syscall(SB),NOSPLIT,$12-28
syscall/asm_nacl_amd64p32.s:TEXT ·Syscall(SB),NOSPLIT,$0-28
syscall/asm_nacl_arm.s:TEXT ·Syscall(SB),NOSPLIT,$0-28
syscall/asm_netbsd_arm.s:TEXT ·Syscall(SB),NOSPLIT,$0-28
syscall/asm_openbsd_arm.s:TEXT ·Syscall(SB),NOSPLIT,$0-28
syscall/asm_plan9_386.s:TEXT ·Syscall(SB),NOSPLIT,$0-32
syscall/asm_plan9_amd64.s:TEXT ·Syscall(SB),NOSPLIT,$0-64
syscall/asm_plan9_arm.s:TEXT ·Syscall(SB),NOSPLIT,$0-32
syscall/asm_solaris_amd64.s:TEXT ·Syscall(SB),NOSPLIT,$0
syscall/asm_unix_386.s:TEXT ·Syscall(SB),NOSPLIT,$0-28
syscall/asm_unix_amd64.s:TEXT ·Syscall(SB),NOSPLIT,$0-56
참조: https://golang.org/doc/asm#directives또한 OS, 아키텍처를 파일 이름으로 지정하여
name_GOOS_GOARCH
구문이 될 수 있습니다.참조: https://golang.org/pkg/go/build/#hdr-Build_Constraints
참고 자료
주요 참조 소스 코드
https://github.com/golang/go/blob/go1.9.3/src/runtime/proc.go
https://github.com/golang/go/blob/go1.9.3/src/runtime/runtime2.go
https://github.com/golang/go/blob/go1.9.3/src/runtime/chan.go
https://github.com/golang/go/blob/go1.9.3/src/runtime/netpoll_epoll.go
https://github.com/golang/go/blob/master/src/runtime/stack.go
원본 코드를 읽을 때 검색하기 어려우니 이렇게 하지 마세요. ↩
따라서 이 경우 GOMAXPROCS가 2라도 M은 4 이상이다. ↩
다른 것도 있을지도 모르지만, 나는 이 두 가지 유형을 만났다. ↩
Reference
이 문제에 관하여(Golang 스케줄에 대해서.), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/takc923/items/de68671ea889d8df6904텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)