[Tucker의 Go 언어 프로그래밍] 25장 채널과 컨텍스트

Coen·2023년 11월 15일
1

tucker-go

목록 보기
18/18
post-thumbnail
post-custom-banner

이 글은 골든래빗 《Tucker의 Go 언어 프로그래밍》의 25장 써머리입니다.

채널과 컨텍스트

25.1. 채널 사용하기

  • 채널 - 고루틴끼리 메시지를 전달할 수 있는 메시지 큐
  • 메시지들은 차례대로 쌓이게 되고 메시지를 읽을 때는 FIFO

25.1.1 채널 인스턴스 생성

var messages chan string = make(chan string)

25.1.2 채널에 데이터 넣기

messages <- "메시지"
  • 채널에 데이터를 넣는 데 <- 연산자를 이용합니다. 우변에 넣을 데이터를 놓으면 우변 데이터를 좌변 채널에 넣게 된다.

25.1.3 채널에서 데이터 빼기

var msg string = <- messages
  • 채널에서 데이터를 빼올 때도 마찬가지로 <- 연산자를 사용한다.
  • 데이터를 빼올 때 만약 채널 인스턴스에 데이터가 없으면 데이터가 들어 올 때까지 대기한다.
func Test_GoroutineChannel(t *testing.T) {
	ch := make(chan int)
	go func() {
		time.Sleep(4 * time.Second)
		ch <- 1
	}()
	msg := <-ch //channel에 데이터가 들어올 때까지 대기한다.
	t.Log(msg)
}

25.1.4 채널 크기

  • 일반적으로 채널을 생성하면 크기가 0인 채널이 만들어진다.
func Test_channel(t *testing.T) {
	ch := make(chan int)
	ch <- 9 //Deadlock 발생
	fmt.Println("Never Print")
}
  • 채널의 크기가 0이고, 데이터를 넣었지만 보관할 곳이 없기 때문에 다른 고루틴에서 데이터를 빼가기를 기다리지만 데이터를 꺼내가지 않아 영원히 기다려 deadlock 발생

25.1.5 버퍼를 가진 채널

  • 내부에 데이터를 보관할 수 있는 메모리 영역을 버퍼라고 부른다.
//버퍼를 가진 채널을 생성하는 법
var messages chan string = make(chan string, 2) //버퍼가 2인 채널 생성
  • 버퍼가 다 차면 빈자리가 생길 때까지 대기한다.

25.1.6 채널에서 데이터 대기

  • 아래는 고루틴에서 데이터를 계속 기다리면서 데이터가 들어오는 예시이다.
func Square(wg *sync.WaitGroup, ch chan int) {
	for n := range ch { //for range 를 사용하면 채널에서 데이터를 계속 기다릴 수 있다.
		log.Printf("Square : %v", n*n)
		time.Sleep(time.Second)
	}
	wg.Done()
}

func Test_WaitingChannel(t *testing.T) {
	var wg sync.WaitGroup
	var ch chan int = make(chan int)

	wg.Add(1)
	go Square(&wg, ch)

	for i := 0; i < 10; i++ {
		ch <- i * 2
	}
    close(ch)
	wg.Wait()
}
  • for range로 채널에서 데이터를 계속 기다릴 수 있다. 하지만 wg.Wait()는 작업이 완료되기를 기다리는데, wg.Done()이 실행되지 않아 데드락이 걸린다.

  • 탈출하고자 하는 경우, 채널에 데이터를 밀어넣는 오퍼레이션 종료 이후 채널을 닫아줘야 한다.

25.1.7 select 문

  • 여러 채널을 동시에 대기하고 싶을 때 사용한다.
func Square(wg *sync.WaitGroup, ch chan int, quit chan bool) {
	for {
		select {
		case num := <-ch:
			log.Println(num)
		case <-quit:
			wg.Done()
			log.Println("Quit")
			return
		}
	}
}

func Test_channelSelect(t *testing.T) {
	var wg sync.WaitGroup
	ch := make(chan int)
	quit := make(chan bool)

	wg.Add(1)
	go Square(&wg, ch, quit)

	for i := 0; ; i++ {
		ch <- i * i
		if i >= 11 {
			quit <- true
			return
		}
	}
	wg.Wait()
}
profile
백엔드 프로그래머
post-custom-banner

0개의 댓글