GOLANG – 동시성

Go 스케줄러

스케줄러(scheduler)는 현재 사용할 수 있는 리소스만으로 처리할 수 있는 일의 양을 효율적으로 분산하는 역할을 담당한다.

Go 런타임은 m:n 스케줄러를 이용해 Go 루틴을 스케줄링 한다.

fork-join concurrency (포크-조인 동시성)

포크 부분은 프로그램을 실행하다가 임의의 시점에 자식 브랜치를 생성하는 것을 표현한다. 조인 부분은 자식 브랜치가 끝나서 부모와 합류하는 것을 나타낸다. sync.Wait()문장과 Go루틴의 결과를 수집한 채널이 조인 지점이 된다.

fair scheduling strategy(균등 스케줄링 전략)

모든 부하를 현재 사용할 수 있는 프로세서로 고르게 나누는 방식
Go 언어에서 Go 루틴은 일종의 테스크(task) 인 반면, 이러한 Go 루틴을 호출하는 문장은 모두 컨티뉴에이션(continuation)이다. Go 스케줄러에서0 사용하는 작업 훔치기 전략(work stealing strategy)에 따르면, 충분히 활용되지 않고 있는 프로세서에게 줄 작업을 다른 프로세서에서 찾는다. 이에 맞는 작업을 발견하면 그 프로세서로부터 훔쳐 오기 때문에 작업 훔치기 전략이라고 부른다. 작업 훔치기 알고리즘은 컨티뉴에이션을 훔쳐서 큐에 저장한다.
스톨링조인(stalling join) 이란 스레드의 실행이 조인에서 멈처셔 다른 할 일 찾기 시작하는 지점이다. 작업 훔치기와 컨티뉴에이션 훔치기는 모두 스톨링 조인이 발생하지만, 작업(테스크) 보다는 컨테뉴에이션에서 더 많이 발생한다

GOMAXPROCS 환경변수

GOMAXPROCS 환경 변수를 이용하면 유저 레벨(user-levvel) Go 코드를 동시에 실행할 수 있는 OS 스레드의 수를 제한할 수 있다.

현재 사용하는 머신의 코어 수보다 적은 값을 GOMAXPROCS 변수에 할당하면 프로그램 성능에 영향을 미칠 수 있다. 또한 현재 사용할 수 있는 코어의 개수보다 큰 값을 GOMAXPROCS에 할당한다고 해서 프로그램 속도가 빨라진다는 법도 없다.

package main

import (
   "fmt"
   "runtime"
)

func getGOMAXPROCS() int {
   return runtime.GOMAXPROCS(0)
}

func main() {
   fmt.Printf("GOMAXPROCS: %dn", getGOMAXPROCS())
}

$ go run maxprocs.go
GOMAXPROCS: 8

$ go versoin
go version go1.13.8

$ export GOMAXPROCS=800; go run maxprocs.go
GOMAXPROCS: 800

select 키워드

Go 언어에서 select 문은 채널에 대한 switch 문과 같다. select 블록을 이용해 여러 개의 채널을 다룰 수 있다. 채널에 대해 논블로킹 방식으로 연산을 수행할 수 있다.

package main

import (
   "fmt"
   "math/rand"
   "os"
   "strconv"
   "time"
)

func gen(min, max int, createNumber chan int, end chan bool) {
   for {
   //select 문은 순차적으로 실행되지 않는다. 모든 채널을 동시에 확인한다.
   //select 문에 있는 채널 중 어떤 것도 사용할 수 있는 상태가 아니라면 어느 한 채널이 사용 가능한 상태가 될 때까지 블록된다.
   //select 문에서 사용 가능한 상태의 채널이 여러개라면 Go 런타임은 그 중 하나를 임의로 선택한다.
      select {
      case createNumber <- rand.Intn(max-min) + min:
      case <-end:
         close(end)
         return
      case <-time.After(4 * time.Second): //알종헌 사건아 지나면 리
         fmt.Println("ntime.After()!")
      }
   }
}

func main() {
   rand.Seed(time.Now().Unix())
   createNumber := make(chan int)
   end := make(chan bool)

   if len(os.Args) != 2 {
      fmt.Println("Please give me an integer!")
      return
   }

   n, _ := strconv.Atoi(os.Args[1])
   fmt.Printf("Going to create %d random numbers.n", n)
   go gen(0, 2*n, createNumber, end)

   for i := 0; i < n; i++ {
      fmt.Printf("%d ", <-createNumber)
   }

   time.Sleep(5 * time.Second)
   fmt.Println("Exiting...")
   end <- true
}

$ go run select.go 
10
Going to create 10 random numbers.
3 12 4 7 2 18 16 3 5 0
time.After()!
Exiting...

Go 루틴 만료시키기

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut elit tellus, luctus nec ullamcorper mattis, pulvinar dapibus leo.

답글 남기기