오늘의 주인공은 바둑 인터뷰에서 나온 만능 GMP 모델 질문의 확장 질문(질문)입니다. 바로 "GMP 모델, 왜 P이 필요한가요?"
더 자세히 알아보겠습니다. 사실 이 인터뷰에서 질문의 본질은 "GMP 모델에서는 왜 G와 M을 직접 묶을 수 없는 걸까요? 너무 번거롭습니다. 왜 그렇게 번거롭습니까? 무슨 문제입니까?"라고 묻는 것입니다. 문제를 해결하려고 하시나요?"
이 기사에서는 GM 및 GMP 모델의 변경 이유를 살펴보겠습니다.static void schedule(G *gp) { ... schedlock(); if(gp != nil) { ... switch(gp->status){ case Grunnable: case Gdead: // Shouldn't have been running! runtime·throw("bad gp->status in sched"); case Grunning: gp->status = Grunnable; gput(gp); break; } gp = nextgandunlock(); gp->readyonstop = 0; gp->status = Grunning; m->curg = gp; gp->m = m; ... runtime·gogo(&gp->sched, 0); }
schedlock
가져오기 방법 글로벌 잠금. schedlock
方法来获取全局锁。gput
方法来保存当前 Goroutine 的运行状态等信息,以便于后续的使用。nextgandunlock
方法来寻找下一个可运行 Goroutine,并且释放全局锁给其他调度使用。runtime·gogo
nextgandunlock
찾기 방법 다음 고루틴이 실행될 수 있으며 다른 스케줄러가 사용할 수 있도록 전역 잠금이 해제됩니다.
전화 런타임·gogo
메소드 , 방금 얻은 다음 실행할 고루틴을 실행하고 다음 스케줄링 라운드에 들어갑니다.
Go1.0.1의 스케줄러 소스코드를 분석해보면 흥미로운 점을 발견할 수 있습니다. 이는 스케줄러 자체(스케줄 방식)입니다. 일반 프로세스에서는 반환되지 않습니다. 즉, 기본 프로세스가 종료되지 않습니다.
🎜🎜🎜G-M 모델 다이어그램🎜🎜🎜 GoroutineA가 완료된 후 GoroutineB를 찾기 시작합니다. B가 발견되면 A의 완료된 스케줄링 권한이 B에 넘겨져 GoroutineB가 됩니다. 스케줄링, 즉 실행 중이 되기 시작합니다. 🎜🎜물론 차단(Blocked)된 G도 있습니다. G가 일부 시스템이나 네트워크 호출을 하고 있어 G가 정지하게 된다고 가정합니다. 이때 M(시스템 스레드)은 커널 큐에 다시 배치되어 새로운 깨우기 라운드를 기다립니다. 🎜🎜🎜🎜GM 모델의 단점🎜🎜🎜🎜GM 모델은 표면적으로는 부서지지 않고 흠 하나 없는 것처럼 보입니다. 그런데 왜 바꾸나요? 🎜🎜Dmitry Vyukov는 2012년에 Go Scheduler에 대한 주요 연구 논문의 주요 대상인 "Scalable Go Scheduler Design Doc"이라는 논문을 발표했습니다. 그는 논문에서 전반적인 이유와 고려 사항을 설명했습니다. . 🎜현재 Goroutine 스케줄러(Go 1.0의 GM 모델 참조)는 Go로 작성된 동시 프로그램, 특히 처리량이 높은 서버 및 병렬 컴퓨팅 프로그램의 확장성을 제한합니다.
구현에는 다음과 같은 문제가 있습니다.
위의 GM 모델의 많은 문제를 해결하기 위해 Go1.1에서 Dmitry Vyukov는 GM 모델을 기반으로 하는 새로운 P(Processor) 구성 요소를 추가했습니다. 그리고 새롭게 발생한 일부 문제를 해결하기 위해 Work Stealing 알고리즘을 구현했습니다.
GMP 모델은 이전 기사 "Go 그룹 친구들이 물었습니다: 제어할 적절한 고루틴 수는 얼마입니까? 이것이 GC와 스케줄링에 영향을 미칠까요?" "에 설명되어 있습니다.
좋다고 생각하는 친구들은 주목해도 좋고 여기서는 반복하지 않겠습니다.
P를 추가하면 어떤 변화가 생길까요? 좀 더 명확하게 얘기해보자.
각 P에는 자체 로컬 큐가 있어 글로벌 큐에 대한 직접적인 의존도가 크게 줄어듭니다. 결과적으로 잠금 경쟁이 줄어듭니다. GM 모델의 성능 오버헤드의 대부분은 잠금 경쟁입니다.
각 P의 상대적 균형에 따라 GMP 모델에도 작업 스틸링 알고리즘이 구현되어 있습니다. P의 로컬 큐가 비어 있으면 실행 가능한 G가 글로벌 큐 또는 로컬 큐에서 도난당합니다. 다른 P를 실행하여 유휴 상태를 줄이고 리소스 활용도를 향상시킵니다.
이때 헷갈려하는 친구들도 있을텐데, 로컬 큐와 Work Stealing 알고리즘을 구현하고 싶다면 직접 M에 추가하면 되지 않을까요? M의 경우 유사한 기능을 얻을 수 있습니다 .
다른 P 구성 요소를 추가하는 이유는 무엇입니까?
M(시스템 스레드)의 위치 지정과 결합하여 이렇게 하면 다음과 같은 문제가 발생합니다.
일반적으로 M의 수가 P보다 많을 것입니다. Go와 마찬가지로 M 개수의 최대 제한은 10000이고, P의 기본 개수는 CPU 코어 개수입니다. 또한 M의 속성으로 인해, 즉 M을 차단하는 시스템 차단 호출이 있어 충분하지 않은 경우에도 M은 계속 증가하게 됩니다.
M이 계속 증가하면 로컬 큐가 M에 마운트되면 로컬 큐도 증가한다는 의미입니다. 로컬 큐 관리가 복잡해지고 Work Stealing 성능이 크게 저하되므로 이는 명백히 불합리합니다.
M 시스템 호출에 의해 차단된 후, 차단되자마자 모든 것을 중지시키는 것이 아니라 실행되지 않은 작업을 다른 사람에게 할당하여 계속 실행되기를 바랍니다.
그러므로 M을 사용하는 것은 무리입니다. 그러면 새로운 컴포넌트 P를 도입하고 로컬 큐를 P에 연결하면 이 문제를 아주 잘 해결할 수 있습니다.
오늘의 글은 Go 언어 스케줄러 전체에 대한 몇 가지 역사적 상황, 원인 분석 및 해결 방법 설명을 결합한 것입니다.
"GMP 모델, 왜 P가 있지?" 이 질문은 시스템 설계 이해와도 같습니다. 이제 많은 사람들이 인터뷰에 응하기 위해 GMP 모델을 외우거나 즉석에서 통과하게 될 것이기 때문입니다. 그리고 그 이면의 실제 이유를 이해하는 것이 우리가 배우고 이해해야 할 것입니다.
무슨 일이 일어나고 있고 왜 일어나는지 알아야만 상황을 깨뜨릴 수 있습니다.
위 내용은 안녕 고 면접관 : GMP 모델, 왜 P가 있나요?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!