Buffered vs Unbuffered Channel

didnlie23·2023년 3월 27일
0

golang

목록 보기
2/3
post-thumbnail

Go에서는 두 가지 타입의 Channel을 지원한다.

Unbuffered Channel

Channel 자체가 근본적으로 Goroutine들 간의 통신을 위해 만들어졌는데, Unbuffered Channel은 Goroutine들 간의 동기적인 통신 구현용으로 적합하다.

생산하는 측은 소비하는 측이 준비될 때까지 대기한다. 생산하는 측과 소비하는 측 둘 다 준비되었을 때, 데이터를 주고받을 수 있도록 설계되었다.

Buffered Channel

Buffered Channel은 내부에 Buffer가 마련되어 있는 Channel이다. 내부의 Buffer는 생산자의 입장에서 데이터를 임시적으로 저장해둘 수 있는 공간이 되어주고, 이는 생산자가 소비자에게 데이터를 비동기적으로 송신할 수 있도록 도와준다.

생산하는 측은 소비하는 측의 준비 여부와는 관계 없이 데이터를 Buffer에 삽입한 후, 자신의 작업을 이어나갈 수 있다. 수신하는 측은 Buffer에서 데이터를 꺼내 소비한다.

Buffer의 크기는 고정되기 때문에, Buffer가 꽉 찬 상태에서는 Unbuffered Channel과 마찬가지로 생산하는 측은 Buffer 내의 데이터가 소비될 때까지 대기한다. 소비하는 측 또한 소비할 데이터가 Buffer에 삽입되기 전까지 대기한다.

성능

두 Channel의 용도에 대해서는 파악했으니, 간단하게 성능에 대해서도 알아보자.

import "testing"

func BenchmarkUnbufferedChannel(b *testing.B) {
	ch := make(chan int)

	go func() {
		for i := 0; i < b.N; i++ {
			ch <- i
		}
		close(ch)
	}()

	for _ = range ch {
	}
}

func BenchmarkBufferedChannel(b *testing.B) {
	ch := make(chan int, 10000)

	go func() {
		for i := 0; i < b.N; i++ {
			ch <- i
		}
		close(ch)
	}()

	for _ = range ch {
	}
}
goos: linux
goarch: amd64
pkg: playground/channel
cpu: Intel(R) Core(TM) i7-8086K CPU @ 4.00GHz
BenchmarkUnbufferedChannel
BenchmarkUnbufferedChannel-12            7479062               169.6 ns/op
BenchmarkBufferedChannel
BenchmarkBufferedChannel-12             17266783                74.86 ns/op
PASS

차이점이라고는 Buffer의 크기밖에 없다. Buffered Channel을 사용했을 때, 보다 더 많은 데이터를 주고받을 수 있었던 이유는 Context Switching 비용이 덜 발생하기 때문이다.

Unbuffered Channel을 사용하면 데이터를 주고받을 때마다 일시적으로 대기 상태가 된다. 대기 상태가 된다는 것은 Context Switching 된다는 것을 의미한다. 반면 Buffered Channel은 내부에 Buffer가 임시 저장 장치로써 존재하기 때문에 Context Switching 되는 빈도수가 Unbuffered Channel을 사용했을 때에 비해 적을 것이다.

※ Goroutine은 Thread와 다르다. Go Runtime에 의해 관리되며, 하나의 Thread 위에서 여러 개의 Goroutine이 번갈아 실행될 수 있다.

profile
with golang

0개의 댓글