[golang] 고루틴(go routine) 예제
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 값을 할당하지 않고 대기하는 의미로 쓰일 수도 있다. (예, 시그널)
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