Golang 스케줄에 대해서.

11302 단어 Go

개시하다


올해 들어 일에 골랑이라고 쓰여 있어서 스케줄을 조사해 봤습니다.투덜거려도 자료가 많지 않으니 정리해 봤다.소스 코드를 참조할 때 Go 1.9.3이 표시됩니다.나는 이해하기 쉬운 부분을 매우 중시하기 때문에 매우 간단하게 설명하였으니 양해해 주십시오.
잘못된 점이 있을 수 있으니 자세한 사람은 부드럽게 말씀해 주세요.

고로틴에 대한 기본적인 이야기입니다.


goroutine는 녹색 라인, 즉 OS의 라인을 직접 사용하지 않았다.따라서 고루틴 제작은 현지 라인을 만드는 것보다 처리 원가가 훨씬 싸다.이 고로틴을 여러 개 만들면 실행 시간이 자동으로 다중 라인으로 실행됩니다.상세한 상황은 후술하다.
그리고 메인 프로그램도 고로틴으로 관리된다.

배차 중인 등장인물


중요한 등장인물은 M, G, P 세 명이다.
  • M(Machine)
  • OS 스레드
  • G(Goroutine)
  • 그대로.
  • P(Processor)
  • 는'메모리 G의 deque'라고 불리는 특수 대기열을 가지고 G를 M에 분배하는 역할을 한다.
  • GOMAXPROCS 환경 변수는 여기에 해당합니다.
  • 실행 환경의 핵심 수를 기본적으로 설정합니다1
  • 이것은 원본 코드에서 m, g, p로 정의됩니다.2

    스케줄링의 기본 메커니즘


    GOMAXPROCS 수량을 위한 M, P 그룹이 준비되어 있습니다.GOMAXPROCS가 2인 경우 대체로 다음과 같은 방식으로 수행됩니다.

    그리고 한 측이 G를 모두 실행하고 한가할 때 다른 P에게서 G의 반을 빼앗는다.

    이 스케줄링 알고리즘은workstealing 알고리즘이라고 한다.이workstealing 알고리즘은 CPU 반사 처리가 매우 효율적이지만 iowait 등 쓸모없이 막힌 처리와는 맞지 않는다.거기서 몇 가지 방법을 만들었어요. 지금부터 설명해 드릴게요.

    상세 진입 전 준비


    필요한 사전 지식을 상세히 설명하다.
  • 글로벌 큐
  • P에 있는 G의 큐와 달리 글로벌 큐가 있습니다.
  • 대개 G는 실행을 기다리는 상태에서 P의 대기열에 들어가지만 일부 경우에는 글로벌 대기열에 들어갑니다.
  • 다음과 같은 경우 글로벌 큐가 제거됩니다.
  • M의 자체 큐가 비어 있을 때 체크 아웃
  • M의 자체 큐가 남아 있더라도 61회마다 체크 아웃(글로벌 큐가 계속 실행되지 않도록 함)
  • sysmon
  • 는 기본적으로 GOMAXPROCS의 수량인 M과 P의 집합이 이동하고 있음을 설명하지만 이와 달리systmon이라는 함수를 계속 집행하는 특별한 M이 존재한다.이것은 P 없이 실행됩니다.
  • 이systmon의 처리 주체는 무한순환이다. 이 순환에서 후술한 넷폴의 검사, 실행 시간이 긴 G의 프레셔스, 필요하면 GC용 G를 전역 대기열에 추가한다.
  • P idle list
  • P가 다른 할 일이 없으면 P idle list에 들어갈 수 있습니다.
  • M idle list
  • 다른 할 일이 없으면 M도 M idle list에 들어갈 수 있다.
  • 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
    
    즉, 실현은 바로 이것이다
  • https://github.com/golang/go/blob/go1.9.3/src/runtime/netpoll.go#L164
  • 참조: https://golang.org/cmd/compile/#hdr-Compiler_Directives
    어셈블리 언어에 정의된 경우 ^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

    참고 자료

  • The Go scheduler - Morsing's blog
  • The Go netpoller - Morsing's blog
  • GOMAXPROCS | Dave Cheney
  • Golang의 소스 코드 연구(二)goroutine의 작업 원리-Qita
  • channel - go routine blocking the others one - Stack Overflow
  • 100만 회의 WebSocket 연결 및 Go|프로그래밍|POSTD
  • Golang 쓰레기 재활용 분석 | Legetkl
  • 주요 참조 소스 코드


  • https://github.com/golang/go/blob/go1.9.3/src/runtime/proc.go
  • systmon,entersycall,exitsyscal,schedule 등 일대

  • https://github.com/golang/go/blob/go1.9.3/src/runtime/runtime2.go
  • G, M, P의 정의

  • https://github.com/golang/go/blob/go1.9.3/src/runtime/chan.go
  • channel
  • https://github.com/golang/go/blob/go1.9.3/src/runtime/netpoll.go

  • https://github.com/golang/go/blob/go1.9.3/src/runtime/netpoll_epoll.go
  • netpoll

  • https://github.com/golang/go/blob/master/src/runtime/stack.go
  • newstack(preempt면)
  • Go1.5부터 시작합니다.이전에는 기본 1입니다.그리고 논리적인 핵심수이기 때문에 하이퍼링크가 있으면 2배다. 
    원본 코드를 읽을 때 검색하기 어려우니 이렇게 하지 마세요. 
    따라서 이 경우 GOMAXPROCS가 2라도 M은 4 이상이다. 
    다른 것도 있을지도 모르지만, 나는 이 두 가지 유형을 만났다. 

    좋은 웹페이지 즐겨찾기