채널 사용하기



이재홍 http://www.pyrasis.com 2014.12.17 ~ 2015.02.07



동기 채널

이번에는 동기 채널의 특성을 좀 더 자세히 알아보겠습니다. 다음은 고루틴과 메인 함수를 번갈아가면서 실행합니다.

package main

import (
	"fmt"
	"time"
)

func main() {
	done := make(chan bool) // 동기 채널 생성
	count := 3              // 반복할 횟수

	go func() {
		for i := 0; i < count; i++ {
			done <- true                // 고루틴에 true를 보냄, 값을 꺼낼 때까지 대기
			fmt.Println("고루틴 : ", i) // 반복문의 변수 출력
			time.Sleep(1 * time.Second) // 1초 대기
		}
	}()

	for i := 0; i < count; i++ {
		<-done                         // 채널에 값이 들어올 때까지 대기, 값을 꺼냄
		fmt.Println("메인 함수 : ", i) // 반복문의 변수 출력
	}
}

make(chan bool)처럼 채널을 생성합니다. 여기서는 채널로 값을 주고 받아도 실제로 사용하지 않으므로 자료형은 큰 의미가 없습니다. make 함수에 매개 변수를 하나만 지정했으므로 동기 채널을 생성됩니다. 비동기 채널과 버퍼는 뒤에서 설명하겠습니다.

먼저 고루틴을 생성하고, 반복문을 실행할 때마다 채널 donetrue 값을 보낸 뒤 1초를 기다립니다.

go func() {
	for i := 0; i < count; i++ {
		done <- true                // 고루틴에 true를 보냄, 값을 꺼낼 때까지 대기
		fmt.Println("고루틴 : ", i) // 반복문의 변수 출력
		time.Sleep(1 * time.Second) // 1초 대기
	}
}()

동기 채널이므로 done에 값을 보내면 다른 쪽에서 값을 꺼낼 때까지 대기합니다. 따라서 반복문도 실행되지 않으므로 “고루틴 : 숫자”가 계속 출력되지 않습니다.

이제 메인 함수에서는 반복문을 실행할 때마다 채널 done에서 값을 꺼냅니다.

for i := 0; i < count; i++ {
	<-done                         // 채널에 값이 들어올 때까지 대기, 값을 꺼냄
	fmt.Println("메인 함수 : ", i) // 반복문의 변수 출력
}

<-done 부분에서 채널에 값이 들어올 때까지 대기합니다. 먼저 앞의 고루틴에서 done에 값을 보냈기 때문에 값을 꺼낸 뒤 다음 코드로 진행합니다. 그리고 고루틴 쪽의 대기도 종료되면서 다시 반복문이 실행된 뒤 채널에 값을 보냅니다. 그리고 메인 함수는 채널에서 값을 꺼내고, 다시 고루틴도 채널에 값을 보냅니다. 따라서 다음과 같이 고루틴 → 메인 함수 → 고루틴 → 메인 함수 순서로 실행됩니다.

실행 결과

고루틴 :  0
메인 함수 :  0
고루틴 :  1
메인 함수 :  1
고루틴 :  2
메인 함수 :  2


그림 34-3 메인 함수와 고루틴 실행 순서

동기 채널은 보내는 쪽에서는 값을 받을 때까지 대기하고, 받는 쪽에서는 채널에 값이 들어올 때까지 대기합니다. 따라서, 동기 채널을 활용하면 고루틴의 코드 실행 순서를 제어할 수 있습니다.


저작권 안내

이 웹사이트에 게시된 모든 글의 무단 복제 및 도용을 금지합니다.
  • 블로그, 게시판 등에 퍼가는 것을 금지합니다.
  • 비공개 포스트에 퍼가는 것을 금지합니다.
  • 글 내용, 그림을 발췌 및 요약하는 것을 금지합니다.
  • 링크 및 SNS 공유는 허용합니다.

Published

01 June 2015