Divide and Conquer
Goroutine 스케줄링 본문
728x90
https://velog.io/@sunaookamisiroko/Goroutine-%EC%8A%A4%EC%BC%80%EC%A4%84%EB%A7%81
고루틴은 (c) N:M 스케줄링을 함
global runqueue에서 M이 G를 하나씩 가져다가 실행
global runqueue는 하나의 자료구조 > M이 동시에 사용하면 race condition 발생 > lock을 사용
그런데, M은 G를 갖기 위해 lock을 기다려야 해서 성능저하로 이어짐
+ 하나의 고루틴의 실행 시간이 길다면 다른 실행되지 않는 고루틴은 기아 상태에 빠질 수 있다
Goroutine locality
func main() {
var wg sync.WaitGroup
wg.Add(10)
for i := 0; i < 10; i++ {
go func() {
defer wg.Done()
doSomething()
}()
}
wg.Wait()
}
main G가 새로운 G를 10개 만듦
func sender(ch chan int) {
for i := 0; i < 10; i++ {
ch <- i
}
close(ch)
}
func reciever(ch chan int) {
for {
msg, ok := <- ch
if !ok {
break
}
process(msg)
}
}
func process(msg int) {
fmt.Println("Reciedved:", msg)
}
func main() {
ch := make(chan int)
go sender(ch)
reciever(ch)
}
다음 예시 코드는 100개의 고루틴으로 동시에 열어서 파일을 만들고 쓰는 작업을 한다
https://changhoi.kim/posts/go/go-scheduler/
package main
import (
"fmt"
"os"
"runtime/pprof"
"sync"
)
func main() {
threadProfile := pprof.Lookup("threadcreate")
fmt.Printf("thread count before start: %d\n", threadProfile.Count())
var wg sync.WaitGroup
wg.Add(100)
for i := 0; i < 100; i++ {
go func(n int) {
defer wg.Done()
filename := fmt.Sprintf("files/%d-file", n)
f, err := os.Create(filename)
if err != nil {
panic(err)
}
defer func() {
if err := f.Close(); err != nil {
fmt.Println(err)
}
err := os.Remove(filename)
if err != nil {
fmt.Println(err)
}
}()
var str []byte
for j := 0; j < 1000; j++ {
str = append(str, byte(j))
}
_, err = f.Write(str)
if err != nil {
panic(err)
}
}(i)
}
wg.Wait()
fmt.Printf("threads count aftre program: %d\n", threadProfile.Count())
}
반응형
'성장캐 > 분산컴퓨팅' 카테고리의 다른 글
Comments