Golang Syntax _8
28. 고루틴
package main import ( "fmt" "time" ) func say(s string) { for i := 0; i < 5; i++ { time.Sleep(1 * time.Millisecond) fmt.Println(s) } } func main() { go say("world") say("hello") } /**** Output **** hello world world hello world hello hello world hello ****************/
- Goroutines은 런타임중에 관리되는 경략 쓰레드이다.
go f(a, b, c)
와같이 사용되며, 새로운 고루틴을 실행한다.- 고루틴은 동일한 주소공간에서 실행되므로, 공유되는 자원의 접근은 반드시 동기화되야한다.
29. 채널
채널은 채널 연산자 <-
를 이용해 값을 주고 받을 수 있는, 타입이 존재하는 파이프이다.
package main import "fmt" func sum(a []int, c chan int) { sum := 0 for _, v := range a { sum += v } c <- sum // send sum to c } func main() { a := []int{7, 2, 8, -9, 4, 0} c := make(chan int) go sum(a[:len(a)/2], c) go sum(a[len(a)/2:], c) x, y := <-c, <-c // receive from c fmt.Println(x, y, x+y) // -5 17 12 }
ch <- v
: v를 ch로 보낸다.
v := <-ch
: ch로부터 값을 받아서 v로 넘긴다.- 맵이나 슬라이스처럼, 채널은 사용되기 전에 생성 되어야한다.
ch := make(chan int)
- 송/수신은 상대편이 준비될때까지 대기한다.
- 채널은 버퍼링될 수 있다. make에서 두번째 인자로 버퍼의 용량을 지정해 줌으로써 해당 버퍼만큼 버퍼링되는 채널을 생성할 수 있다.
ch := make(chan int, 100)
package main import "fmt" func main() { c := make(chan int, 2) c <- 1 c <- 2 fmt.Println(<-c) fmt.Println(<-c) }
만약 버퍼를 1을 잡게 된다면 에러가 발생하게 된다.
30. Range와 Close
데이터 송신측은 더 이상 보낼 값이 없음을 알리기 위해 채널을 close할 수 있다.
수신자는 아래와 같은 수신 코드의 두번째 인자를 줌으로써 채널이 닫혓는지 테스트 할 수 있다.
v, ok := <- ch
와 같이 사용하며, 만약 채널이 닫겨있다면 ok
엔 false
가 들어가게 된다.
또한 for i := range ch
와 같은 반복문은 채널이 닫힐 때 까지 계속해서 값을 받는다.
package main import ( "fmt" ) func fibonacci(n int, c chan int) { x, y := 0, 1 for i := 0; i < n; i++ { c <- x x, y = y, x+y } close(c) } func main() { c := make(chan int, 10) go fibonacci(cap(c), c) for i := range c { fmt.Println(i) } }
- 주의할 점은 채널은 송신측만 닫을수 있으며, 수신측에선 닫을 수 없다.
- 채널은 파일과 다르기에 항상 닫을 필요가 없으며,
채널을 닫는 동작은 오로지 수신측에게 더이상 보낼값이 없다고 말해야 할 때만 행해지면 된다.