[Go] select를 활용한 비동기 프로그래밍

natae·2022년 10월 23일
0

Golang

목록 보기
11/11

개요

  • 버퍼 없는 채널 사용시 쓰기, 읽기가 동시에 일어나지 않으면 블락이 발생할 수 있음
  • select를 통해 비동기로 구현
  • 아래 예시는 이번 주제를 설명하기에 적절하지 않을 수 있음 (채널과 고루틴 없이 충분히 구현 가능)
    • 하지만 핵심 부분만 간단하기 설명하기 위함
    • 실제 참고한 코드를 보는 걸 추천 (참고문헌의 loop 함수)

코드 및 출력

  • 예시 프로그램
    • 1초 주기로, 무작위 수를 발생시켜, 짝수일 경우 출력
    • 10초 이후부터 출력

동기 코드

package study

import (
	"fmt"
	"math/rand"
	"time"
)

type Item struct {
	num int
}
func ChanWithSync() {
	externalItemChan := make(chan Item)

	go func() {
		for {
			<-time.After(time.Second)
			result := rand.Intn(10)
			if result%2 == 0 {
				fmt.Println("Add start")
				externalItemChan <- Item{num: result}
				fmt.Println("Add end")
			}
		}
	}()

	// After enough time has passed...
	time.Sleep(10 * time.Second)

	for {
		item := <-externalItemChan
		fmt.Println(item.num)
	}
}
  • 출력
Add start
# After 10 seconds
Add end
8
Add start
Add end
0
Add start
Add end
6
Add start
Add end
0
  • 분석
    • 외부 채널(externalItemChan)에 Item을 넘겨주는 순간부터, 고루틴이 블락
    • 10초간 모든 고루틴이 정지됨

비동기 코드

package study

import (
	"fmt"
	"math/rand"
	"time"
)

type Item struct {
	num int
}

func ChanWithAsync() {
	externalItemChan := make(chan Item)

	go func() {
		randNumChan := make(chan int)
		evenNumSlice := []int{}
		for {
			var item Item
			var itemChan chan Item
			if len(evenNumSlice) > 0 {
	            // Enable itemChan
				item = Item{num: evenNumSlice[0]}
				itemChan = externalItemChan
			}

			select {
			case <-time.After(time.Second):
				go func() {
					randNumChan <- rand.Intn(10)
				}()

			case result := <-randNumChan:
				if result%2 == 0 {
					fmt.Println("Add start")
					evenNumSlice = append(evenNumSlice, result)
					fmt.Println("Add end")
				}

			case itemChan <- item:
				evenNumSlice = evenNumSlice[1:]

			}
		}
	}()

	// After enough time has passed...
	time.Sleep(10 * time.Second)

	for {
		item := <-externalItemChan
		fmt.Println(item.num)
	}
}
  • 출력
Add start
Add end
Add start
Add end
Add start
Add end
# After 10 seconds
8
0
6
Add start
Add end
0
Add start
Add end
4
  • 분석
    • 무작위 수 생성 시 채널(randomNumChan)을 사용하고, 별도의 고루틴으로 데이터를 넣기 때문에 1초당 무작위 수 생성 보장하며, 블락되지 않음
    • 출력할 값을 슬라이스에 저장하여, 나중에 한번에 데이터를 넘겨줄 수 있음
    • 외부 채널(externalItemChan)에 Item을 넘겨주는 과정에서 블락되더라도, 다른 작업에 영향을 끼지치 않음

결론

  • select로 채널의 값을 읽기뿐만아니라, 쓰기도 가능
    • 채널이 nil일 경우 무시(읽기, 쓰기)
    • 채널이 블락된 경우 무시(읽기, 쓰기)

참고문헌

profile
서버 프로그래머

0개의 댓글