golang

[golang] 고루틴(go routine) 예제

'김용환' 2017. 9. 8. 16:56



golang에는 고루틴이라는 concurrency를 제공한다.


아래 예제는 한번에 동시에 실행하는 예제로서 클로져를 실행하는 코드이다.

 fmt.Scanln()은 입력을 기다리는 함수로서 고루틴이 모두 완료할 때까지 기다린다. 

package main

import (
"fmt"
"time"

)

func main() {
for i := 0; i <= 5; i++ {
go func() {
t := time.Now()
fmt.Println(t)
fmt.Println("Hello, World")
}()
}

fmt.Scanln()

}




결과는 다음과 같다.


2017-09-08 20:18:30.304976947 +0900 KST

Hello, World

2017-09-08 20:18:30.304985595 +0900 KST

Hello, World

2017-09-08 20:18:30.305044938 +0900 KST

Hello, World

2017-09-08 20:18:30.305051478 +0900 KST

Hello, World

2017-09-08 20:18:30.305007134 +0900 KST

Hello, World

2017-09-08 20:18:30.305108262 +0900 KST

Hello, World





runtime.GOMAXPROCS(n)은 프로세서를 얼마나 사용할지 cpu에 알린다.


package main

import (
"fmt"
"time"
"runtime"
)

func main() {
runtime.GOMAXPROCS(5)

//for i := 0; i <= 9000000 * 900000; i++ {
for i := 0; i <= 5; i++ {
go func() {
t := time.Now()
fmt.Println(t)
fmt.Println("Hello, World")
}()
}

fmt.Scanln()

}


cpu 모니터링을 해보면 확실히 알 수 있다.




모든 cpu를 활용하고 싶다면 runtime.NumCPU() 코드를 사용한다.

package main

import (
"fmt"
"time"
"runtime"
)

func main() {
fmt.Println(runtime.NumCPU())
runtime.GOMAXPROCS(runtime.NumCPU())

//for i := 0; i <= 9000000 * 900000; i++ {
for i := 0; i <= 5; i++ {
go func() {
t := time.Now()
fmt.Println(t)
fmt.Println("Hello, World")
}()
}

fmt.Scanln()

}



참고로 go 1.5부터는 rutnime.GOMAXPROCS()를 설정하지 않으면 모든 cpu를 사용하는 것이 디폴트이다.



다음은 channel 예제이다. channel은 go 루틴에서 사용되는 공용 변수이다. 

package main

import (
"fmt"
)

func multifly(value int, ch chan int) {
ch <- value * value
}

func main() {
channel := make(chan int)
go multifly(10, channel)
result := <-channel
fmt.Println(result)
}

채널(channel)을 생성하고 가지고 논 다음, 채널(channel) 값을 일반 변수에 저장한다. 



결과 값은 100이다.



참고로 multifly를 호출할 때 go를 사용하지 않으면 deadlock 에러가 발생한다.


fatal error: all goroutines are asleep - deadlock!



채널은

channel <- 값 : channel에 값 저장
x: <- channel : 채널에 값이 저장될 때까지 기다리고 x에 값을 할당한다. 



하지만 channel 값을 할당하지 않고 대기하는 의미로 쓰일 수도 있다. (예, 시그널)

package main


func multifly(value int, ch chan int) {
ch <- value * value
}

func main() {
channel := make(chan int)
go multifly(10, channel)
<-channel
}




채널에 2개의 버퍼를 사용하고 싶다면 다음과 같이 사용한다. 

buffer := make(chan bool, 2)



운영 체제 시그널을 고루틴으로 처리할 수 있다. 


package main

import (
"fmt"
"os/signal"
"os"
"syscall"
)

func main() {
sigs := make(chan os.Signal, 1)
done := make(chan bool, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
go func() {
sig := <-sigs
fmt.Println()
fmt.Println(sig)
done <- true
}()

fmt.Println("awaiting signal")
<-done
fmt.Println("exiting")
}


실행결과는 다음과 같다. 중간에 Ctrl+C(SIGINT)를 보내야 종료된다.



$ go run Test.go

awaiting signal

^D

^E

^C

interrupt

exiting