티스토리 뷰

golang

Go runtime AND goroutine

주먹불끈 2019. 7. 23. 20:20

개요

 

Go runtime goroutine 대하여 정리해보고자 한다.

- 여기에 scheduler, queue, work stealing 등의 키워드를 둘러보겠음

 

참고서적: Concurrency in GO http://aladin.kr/p/YLCKv

- 6. 고루틴과 런타임

참고 링크들 (이미지 출처)

- Blog posting: https://www.ardanlabs.com/blog/2018/08/scheduling-in-go-part2.html

- Blog posting: https://rakyll.org/scheduler/

- YouTube: https://youtu.be/Yx6FBsGNOp4

 

 

세가지 요소. Process, OS Thread, Goroutine

 

인터넷의 몇몇 그림들을 보자. 보니깐 헷갈리드라

우선 아래 그림을 보자. 요소를 간략히 보자

 

1) M: Machine 의미하며 OS Thread 이다. OS Thread 부르겠다.

2) P: Logical Process 의미하며 Context 로도 불린다. Process 부르겠다.

3) G: goroutine 이다.

 

- goroutine OS Thread 위에서 돌아가며

- OS Thread 실제로 실행되려면 Process 하나를 잡고 있어야 한다.

 

- 각각의 Process 에서 돌아갈 준비가 되어 있는 goroutine 들은 LRQ 에서 대기하고 있는다.

- Local Runable Queue 라고 부르겠다.

- 그리고, Global Runable Queue 별도로 있다.

 

처음 접하시는 분들은 무슨 말인지 이해가 안되실거다 일단 넘어가자.

출처: https://www.ardanlabs.com/blog/2018/08/scheduling-in-go-part2.html

 


 

 

유튜브에 나오는 이미지를 캡처했는데 나는 그림이 낫다.

반복과 중복이 난무하지만 이런것이 머리속에 남기기에 도움이 된다고 생각한다.

 

출처: : https://youtu.be/Yx6FBsGNOp4

 

1) Processors Logical CPU 의미하는데 보통 CPU 사양에서 4 core 8 thread 라고 할때의 8 thread 의미하는 것이다.

2) OS Threads OS 스케쥴링 해주는 하나의 프로그램 수행 공간이라 보면 된다.

3) goroutine Go runtime 스케쥴링 해주는 경량의 thread 라고 보면 된다.

 


 

 

1. Process

 

Context 라고도 한다. 코드가 실행되려면 CPU 메모리 공간이 있어야 한다.

진짜 (손에 잡히는 ?) 자원이라고 생각하자

 

1) Process 개수는 runtime.GOMAXPROCS() 설정할 있다.

2) logical CPU 개수는 runtime.NumCPU() 알아낼 있다.

3) 따라서 runtime.GOMAXPROCS(runtime.NumCPU()) 라고 하면

- 프로세스의 개수를 컴퓨터가 실제로 병렬적으로 사용할 있는 최대치로 쓰겠다고 하는것이다.

- 언듯 Golang 최신버전에선 이게 불필요하다고도 들었는데 일단 skip 하겠음

 

 

logical CPU 무엇인가?

 

컴퓨터의 CPU 사양에 6 core 12 thread 라고 되어 있으면

- 6 core 물리적 CPU 개수이고, 12 thread 논리적 CPU 개수이다.

- 물리적으로는 6개의 core 존재해서 6개의 일을 병렬적으로 있지만 (= 일하는 사람이 6)

- 논리적으로  이걸 최적화 해서 (Intel Hyper Threading, AMD SMT Simultaneous Multi-Threading)

- 하나의 일을 하는 중의 빈틈에 다른 일을 해줘서 하나의 core 개의 일을 (=Thread) 있게 해주는

- 실제로는 core * 2 성능이 나오는 것도 아니고,

- 또한 프로그램이 여기에 최적화 되어 있어야 한다.

따라서 진짜 병렬적으로 (=같은 시간에 동시에) 여러 일을 있는 개수는 12 개가 되는 것이다.

 

2. OS Thread

 

컴퓨터의 CPU core (또는 논리적인 CPU Thread) 개수의 한계가 있다. 병렬적으로 돌릴 있는 프로그램의 개수 제한이 있다는 거다.

그런데 심지어 싱글코어 에서도 우리는 프로그램을 여러 돌린다. 어떻게?

 

HW 적으로는 개수의 한계가 있지만

SW 적으로 (여기서는 OS 레벨에서) 여러 개의 Thread 생성해서 프로그램마다 할당해주는 것이다.

그럼 할당된 Thread (위의 프로그램) 마다 CPU 써야하는데 어떻게 할당해주지?

 

그냥 0.000001 초씩 돌아가며 수행해주면 사람들은 멍청하게도 프로그램이 동시에 수행되는줄 알겠지? (실제 0.000001 초라는 것은 아님)

- 동영상도 보면서 음악도 틀어놓고 웹서핑도  하는거지

- 어짜피 영화도 24장의 정지화면을 빨리 돌려주면 움직이는걸로 착각하잖아 하하

 

3. Goroutine

 

고루틴은 OS Thread 같다. 그런데 다르다.

1) 코루틴이다 (비선점형이라고만 알고 넘어가자)

2) Go runtime 관리해준다.

- , OS Thread OS 생성하고 관리해주는데

- Goroutine Go runtime 생성하고 관리해주는 것이다.

 

여기에서 n:m 이라는 표현이 나온다.

1) 1:1 이라면 1개의 user level thread 1개의 OS Thread 위에서 돌아가는 거다.

2) n:1 이라면 n개의 user level thread 1개의 OS Thread 위에서 돌아가는 거다.

3) m:n 이라면 m개의 user level thread n개의 OS Thread 위에서 돌아가는 거다

고언어는 goroutine 이라는 user level thread m개가 n 개의 OS Thread 위에서 돌아가는 것이다.

 

OS Thread 있는데 goroutine 쓰는 걸까?

줄로 말하자면  엄청 경량이다. 가볍게 휙휙 쓰기 좋다는 것이다.

 

Work stealing. especially continuation stealing

 

아래 이미지를 보자

 

1) 프로세스들이 P1, P2 있고,

2) OS Thread  (M) 5개가 있다.

- 그런데 살아있는 넘은 개이며, 각각 P1, P2 위에서 동작중이다.

3) runnable goroutine 들이 파란 동그라미 들이며,

- 각각 global runable queue local runable queue 대기하고 있다가 하나씩 실행되고 있다.

 


 

< 출처: https://rakyll.org/scheduler/>

 

Work stealing 이란 뭔가?

 

별거 아니다. 만약 P2 local queue 대기중이 goroutine 실행하고 나면 할게 없다.

당신이 사장님이면 이녀석을 놀게 놔둘 것인가? 냉큼 일을 던져줄 수도 있겠다.

하지만 사랑받는, 눈치빠른 미생의 직원이라면? 적극적으로 다른 Process 들의 queue 챙겨보고

대기중인 녀석을 훔쳐서라도 일을 한다. 일을 훔쳤으니깐 work stealing 이다.

 

Task stealing continuation stealing

 

work stealing 크게 Task stealing 과 continuation stealing 으로 나눌 있다.

- task stealing child stealing 으로 부르기도 한다.

 

1) 결론부터 말하자면 (TL;DR) continuation stealing 낫다

2) 그런데 컴파일러가 이걸 지원해줘야 한다.

3) 그런데 Golang 컴파일러는 이걸 지원한다. 하하하

 

continuation stealing 나은 이유

 

Task stealing 과 continuation stealing 동작방식 설명부터 먼저 해줘야 겠지만 우선 이유부터 적어보겠음

1) 고루틴이 분기되었다가 (fork) 합류되는 지점 (join) 에서의 지연이 없으며

2) 동작하는 단계가 조금 적다.

3) 동작하는 순서가 sequential 하다. task stealing 무작위적임

 

실제 동작을 말로 설명하고 비교해보기

 

일일이 그림을 그릴  자신이 없어서 글로 시도해

Process 2개가 있다고 하자. P1, P2

 

task stealing

continuation stealing

1) P1 에서 main routine (=역시 goroutine 이다) 시작한다.

2) goroutine 실행한다

- 시점에 실행해야 goroutine 2가지 이다.

(1) main goroutine 남은 코드들 (=continuation)

(2) 방금 fork goroutine

3) task stealing P1 에서 main goroutine 남은 부분을 계속 실행하고

- goroutine P1 대기열, queue 꽁무니에 넣어둔다.

4) 한편, 일이 없어서 매의 눈으로 다른 Process queue 째려보던 P2

5) P1 queue 들어온 goroutine 보게 되고, 잽싸게 task stealing 한다.

1) P1 에서 main routine (=역시 goroutine 이다) 시작한다.

2) goroutine 실행한다

- 시점에 실행해야 goroutine 2가지 이다.

(1) main goroutine 남은 코드들 (=continuation)

(2) 방금 fork goroutine (여기까진 똑같음)

3) continuation stealing P1 에서 goroutine 실행하고

- main goroutine P1 대기열, queue 꽁무니에 넣어둔다.

4) 한편, 일이 없어서 매의 눈으로 다른 Process queue 째려보던 P2

5) P1 queue 들어온 main goroutine 남은 부분인

continuation 보게 되고, 잽싸게 task stealing 한다.

 

가지만 짚어보자.

 

1) 실행하다가 goroutine 실행하는 시점은 언제일까?

- 시점에 실행되었으면 하는 기능이 있는 것이다. 그렇다면 바로 실행해주면 좋다.

- continuation stealing 바로 그렇다. 실행하고 있던 main goroutine queue 넣어두고, 방금 fork goroutine 실행하는 것이다.

이것은 마치 우리가 함수를 호출했을때에 context switching 일어나는 것을 떠올리게 한다.

2) goroutine 실행한 main goroutine 보통 다음에 무엇을 할까?

- 보통 머지 않아서 fork goroutine 수행을 마치고 join 할때까지 기다리고 있는다.

- 별달리 하는게 없을 가능성이 높다는 거다. 따라서 queue 넣어두는 것이 합당해 보인다.

 

(언급할 타이밍이 없었는데) queue 들은 양방향으로 넣고 있다.

- Process 자신의 queue 넣고 뺄때는 tail 쪽을 이용하지만

- stealing 할때는 head 쪽에서 빼내간다.

 

 

(참고) GRQ - Global Runable Queue 대하여

 

존재 이유에 대한 설명이 없었다.

- 언제 GRQ 넣는지는 생략 (사실 찾다가 일단 넘어감)

 

스케쥴링을 때마다 아래와 같은 과정을 거친다.

링크: https://go.googlesource.com/go/+/master/src/runtime/proc.go

 

runtime.schedule() {
    // only 1/61 of the time, check the global runnable queue for a G.
    // if not found, check the local queue.
    // if not found,
    //     try to steal from other Ps.
    //     if not, check the global runnable queue.
    //     if not found, poll network.
}

1) 61번에 1 정도는 GRQ 대기중인 goroutine 있는지 체크하고

2) 없으면 local queue 체크한다음

3) 거기도 없으면 다른 Process LRQ 체크하고

4) 그래도 없으면, 다시 한번 GRQ 체크

5) 마지막으로 network 쪽을 poll 해준다.

 


반응형
반응형
잡학툰 뱃지
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함