이번 포스팅에서는 고루틴과 채널을 소개합니다. 이것은 go에서 가장 유용한 구조 중 2가지입니다. 함께 적절하게 사용하면 개발자는 동시성을 처리할 때 뛰어난 유연성을 얻을 수 있습니다. 인터뷰에서 가장 흔히 나오는 주제 중 하나입니다.
go에서 간단한 생산자 소비자 패턴을 구현합니다.
var buffer = make(chan int, 5) func produce(wg *sync.WaitGroup) { defer wg.Done() for i := 0; i < 10; i++ { buffer <- i time.Sleep(time.Millisecond * time.Duration(rand.Intn(100))) } fmt.Println("producer done") } func consume(wg *sync.WaitGroup) { defer wg.Done() for data := range buffer { fmt.Println(data) time.Sleep(time.Millisecond * time.Duration(rand.Intn(400))) } fmt.Println("consumer done") } func main() { var producerWg sync.WaitGroup var consumerWg sync.WaitGroup producerWg.Add(1) go produce(&producerWg) go func() { producerWg.Wait() close(buffer) fmt.Println("closed channel") }() consumerWg.Add(1) go consume(&consumerWg) consumerWg.Wait() fmt.Println("done") }
이것은 가장 간단한 구현 중 하나입니다. 하지만 그 패턴은 꽤 흔해요. 값을 '생성'하는 스레드와 값을 '소비'해야 하는 스레드가 있습니다. golang에서는 스레드 간에 이러한 값을 전달하는 방법이 채널입니다.
정수용 채널을 만드는 것부터 시작합니다. 그런 다음 생산자 및 소비자 기능을 구현하는 루틴을 만듭니다.
모든 멀티스레드 상황에서는 동기화가 문제입니다. Golang은 동기화를 구현하기 위한 수단 중 하나로 WaitGroup을 만들었습니다. 이는 단순히 카운터로 작동하며 동기화가 필요한 스레드는 카운트가 0이 될 때까지 기다립니다. 제어 스레드는 Done() 함수를 사용하여 카운터를 감소시킵니다.
이 문제에서는 생산자와 소비자 모두에 대해 WaitGroup을 만들고 둘 다 1로 계산되도록 초기화합니다(Add() 함수 사용).
메인 스레드는 생산자, 소비자를 시작하고 생산자를 기다린 다음 소비자가 완료될 때까지 기다리는 인라인 스레드를 시작합니다.
생산자 스레드가 정상적으로 데이터 전송을 시작합니다. 완료되면 WaitGroup을 사용하여 채널로의 전송이 완료되었음을 알립니다. 인라인 고루틴은 채널을 닫는 생산자 WaitGroup을 기다립니다. 채널이 닫히지 않으면 소비자는 더 많은 데이터를 기다리며 영원히 잠들게 되며 프로세스는 절대 종료되지 않습니다.
소비자에게 더 이상 데이터가 없으면(채널이 닫혀서) 두 번째 WaitGroup에 완료되었음을 알립니다.
생산자 및 소비자 스레드를 시작한 기본 스레드는 소비자 WaitGroup이 완료를 허용할 때까지 기다립니다. 이렇게 하면 메인 스레드가 조기에 종료되어 프로세스의 모든 스레드가 종료되는 것을 방지할 수 있습니다.
이것이 생산자-소비자 패턴을 구현하는 유일한 방법은 아닙니다.
프로덕션 코드에 대해 해결해야 할 SIGTERM 및 SIGINT와 같은 신호의 외부 종료와 같은 몇 가지 문제도 있습니다. 기본을 보여주는 간단한 데모입니다.
그렇다면 어떻게 구현하시겠습니까? 위 구현에서 누락된 것은 무엇입니까? 아래에 의견이나 다른 구현에 대한 링크를 게시하세요.
감사합니다!
이 게시물과 이 시리즈의 모든 게시물에 대한 코드는 여기에서 확인할 수 있습니다
위 내용은 생산자-소비자 패턴의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!