이 름 : 바다아이
|
조회수 : 9176
짧은 주소 : https://www.bada-ie.com/su/?831591799905
서두에 가장 중요한 것 이야기 드립니다.
채널에 빈값이 오면 먹통 됩니다. 이 점은 생각하고 작업 하셔야 합니다.
채널(channel)은 두 고루틴이 서로 통신하고 실행흐름을 동기화하는 수단을 제공한다. 다음은 채널을 사용하는 예제 프로그램이다.
package main
import (
"fmt""time"
)
funcpinger(c chanstring) {
for i := 0; ; i++ {
c <- "ping"
}
}
funcprinter(c chanstring) {
for {
msg := <- c
fmt.Println(msg)
time.Sleep(time.Second * 1)
}
}
funcmain() {
var c chanstring = make(chanstring)
go pinger(c)
go printer(c)
var input string
fmt.Scanln(&input)
}
이 프로그램은 "ping"을 끊임없이 출력할 것이다(중단하려면 엔터 키를 친다).
채널의 타입은 chan이라는 키워드 다음에 채널에 전달되는 것의 타입을 지정해서 나타낸다
(여기서는 문자열을 전달한다). <-(왼쪽 화살표) 연산자는 채널에 메시지를 전달하고 채널로부터
메시지를 전달받는 데 사용한다. c <- "ping"은 "ping"을 전달한다는 의미다. msg := <- c는
메시지를 받아 그것을 msg에 저장한다는 의미다. fmt가 나오는 줄은 fmt.Println(<-c)라고도 작성할 수 있다.
이 경우 앞의 줄을 제거해도 된다.
이 같은 식으로 채널을 이용하면 두 고루틴이 동기화된다. pinger가 메시지를 채널에 전송하려고 시도할
경우 printer가 해당 메시지를 받을 준비가 될 때까지 대기할 것이다(이것은 블로킹으로 알려져 있다).
이번에는 프로그램에 다른 전달자를 추가해서 무슨 일이 일어나는지 살펴보자. 다음 함수를 추가한다.
funcponger(c chanstring) {
for i := 0; ; i++ {
c <- "pong"
}
}
그리고 main 함수를 다음과 같이 수정한다.
funcmain() {
var c chanstring = make(chanstring)
go pinger(c)
go ponger(c)
go printer(c)
var input string
fmt.Scanln(&input)
}
이제 프로그램에서는 "ping"과 "pong"이 번갈아 가면서 출력될 것이다.
채널 방향
채널 타입에 방향을 지정할 수 있는데, 그렇게 함으로써 채널이 보내거나 받기만 하도록 제한할 수 있다.
예를 들어, pinger 함수의 서명을 다음과 같이 변경할 수 있다.
funcpinger(c chan<- string)
이제 c는 보내기만 할 수 있다. c로부터 메시지를 받으려고 하면 컴파일 오류가 발생할 것이다.
이와 비슷하게 출력기를 다음과 같이 변경할 수 있다.
funcprinter(c <-chanstring)
이러한 제한이 없는 채널을 양방향 채널이라 한다. 양방향 채널은 전송 전용 채널이나 수신 전용 채널에 인자로
받는 함수에 전달할 수 있지만 그 역은 성립하지 않는다.
SelectGo에는 switch와 비슷하게 동작하지만 채널에 대해서만 동작하는 select라는 특별한 구문이 있다.
funcmain() {
c1 := make(chanstring)
c2 := make(chanstring)
gofunc() {
for {
c1 <- "from 1"
time.Sleep(time.Second * 2)
}
}()
gofunc() {
for {
c2 <- "from 2"
time.Sleep(time.Second * 3)
}
}()
gofunc() {
for {
select {
case msg1 := <- c1:
fmt.Println(msg1)
case msg2 := <- c2:
fmt.Println(msg2)
}
}
}()
var input string
fmt.Scanln(&input)
}
이 프로그램은 "from 1"을 2초마다 출력하고 "from 2"를 3초마다 출력한다. select는 준비된 첫 번째 채널을
골라 해당 채널로부터 메시지를 받는다(또는 해당 채널로 메시지를 보낸다). 하나 이상의 채널이 준비되면
어느 채널로부터 메시지를 받을지 무작위로 선택한다. 준비된 채널이 없으면 사용 가능해질 때까지 문장 실행이
차단된다.
select 구문은 제한 시간을 구현할 때 자주 사용된다.
select {
case msg1 := <- c1:
fmt.Println("Message 1", msg1)
case msg2 := <- c2:
fmt.Println("Message 2", msg2)
case <- time.After(time.Second):
fmt.Println("timeout")
}
time.After는 채널을 생성한 후 지정한 시간이 지나면 현재 시간을 해당 채널로 보낸다
(여기서는 현재 시간에 관심을 두지 않으므로 변수에 저장하지 않았다). 아울러 default 케이스를 지정할 수도 있다.
select {
case msg1 := <- c1:
fmt.Println("Message 1", msg1)
case msg2 := <- c2:
fmt.Println("Message 2", msg2)
case <- time.After(time.Second):
fmt.Println("timeout")
default:
fmt.Println("nothing ready")
}
default 케이스는 준비된 채널이 없을 경우 즉시 실행된다.
버퍼 채널
채널을 만들 때 make 함수에 두 번째 매개변수를 전달하는 것도 가능하다.
c := make(chanint, 1)
이렇게 하면 용량이 1인 버퍼 채널이 만들어진다. 보통 채널은 동기적으로 동작한다.
즉, 채널의 양쪽이 다른 쪽이 준비될 때까지 기다린다. 버퍼 채널은 비동기적이다.
즉, 메시지를 보내거나 받을 때 채널이 이미 꽉 차 있지 않는 이상 기다리지 않는다.
출처 : http://www.codingnuri.com/golang-book/10.html#section2
|
|
번 호
카테고리
제 목
이름
조회수
Copyright ⓒ 2001.12. bada-ie.com. All rights reserved.
이 사이트는 리눅스에서 firefox 기준으로 작성되었습니다. 기타 브라우저에서는 다르게 보일 수 있습니다.
[ Ubuntu + GoLang + PostgreSQL + Mariadb ]
서버위치 : 오라클 클라우드 춘천 실행시간 : 0.07876 초 to webmaster... gogo sea. gogo sea.