예, 복잡합니다.하지만 상황을 훨씬 더 간단하게 만들 수있는 몇 가지 경험 규칙이 있습니다.
- 글로벌 범위의 채널에 액세스하는 대신 go-routine에 전달 하는 채널에 대해 형식 인수를 사용하는 것을 선호합니다 . 이 방법으로 더 많은 컴파일러 검사를 얻을 수 있으며 모듈화도 향상됩니다.
- 특정 go-routine ( 'main'포함)의 동일한 채널에서 읽기와 쓰기를 모두 피하십시오 . 그렇지 않으면 교착 상태가 훨씬 더 위험합니다.
다음은이 두 가지 지침을 적용하는 프로그램의 대체 버전입니다. 이 사례는 채널에서 많은 작가와 한 명의 독자를 보여줍니다.
c := make(chan string)
for i := 1; i <= 5; i++ {
go func(i int, co chan<- string) {
for j := 1; j <= 5; j++ {
co <- fmt.Sprintf("hi from %d.%d", i, j)
}
}(i, c)
}
for i := 1; i <= 25; i++ {
fmt.Println(<-c)
}
http://play.golang.org/p/quQn7xePLw
단일 채널에 기록하는 5 개의 go-routine을 생성하며 각각 5 번 기록합니다. 기본 go-routine은 25 개의 메시지를 모두 읽습니다. 표시되는 순서는 종종 순차적이지 않습니다 (즉, 동시성이 분명함).
이 예는 Go 채널의 기능을 보여줍니다. 여러 작성자가 하나의 채널을 공유 할 수 있습니다. Go는 메시지를 자동으로 인터리브합니다.
두 번째 예에서 볼 수 있듯이 한 채널에있는 한 명의 작성자와 여러 명의 독자에 대해서도 동일하게 적용됩니다.
c := make(chan int)
var w sync.WaitGroup
w.Add(5)
for i := 1; i <= 5; i++ {
go func(i int, ci <-chan int) {
j := 1
for v := range ci {
time.Sleep(time.Millisecond)
fmt.Printf("%d.%d got %d\n", i, j, v)
j += 1
}
w.Done()
}(i, c)
}
for i := 1; i <= 25; i++ {
c <- i
}
close(c)
w.Wait()
이 두 번째 예 에는 메인 고 루틴에 부과 된 대기가 포함되어 있습니다. 그렇지 않으면 즉시 종료되고 다른 5 개의 고 루틴이 조기에 종료됩니다 ( 이 수정에 대한 olov 덕분에 ) .
두 예 모두 버퍼링이 필요하지 않았습니다. 일반적으로 버퍼링을 성능 향상기로 만 보는 것이 좋은 원칙입니다. 프로그램이 교착하지 않는 경우 없이 버퍼, 그것은 교착하지 않습니다 과 중 버퍼 (하지만 그 반대는 아니다 항상 true). 따라서 또 다른 경험 규칙으로 버퍼링없이 시작한 다음 필요에 따라 나중에 추가하십시오 .
original, hi from 4
...