18.3. 프로그램언어 고(Go)의 고루틴과 채널의 활용

프로그램언어 고(Go)에서의 채널의 여러가지 활용법

고(Go)언어의 채널에는 다음과 같은 여러 가지 활용법이 있습니다.

package main

import "fmt"

func main() {

    // 버퍼가 없는 채널
    ch := make(chan int) 

    // 버퍼가 있는 채널
    ch2 := make(chan string, 2)
}

위의 예제코드와 같이 채널을 만들 때 버퍼의 유무에 따라 다음과 같이 활용할 수 있습니다.

1. 버퍼가 없는 채널
– 데이터 전송 시 보내는 쪽과 받는 쪽이 모두 준비된 경우에만 동작합니다.
– 주로 동기화나 데이터 흐름 제어에 사용합니다.

ch := make(chan int)

go func() {
    ch <- 1 // 받는 쪽이 준비될 때까지 블로킹
}() 

i := <-ch // 보내는 쪽이 준비될 때까지 블로킹

2. 버퍼가 있는 채널
- 버퍼 크기 만큼의 데이터를 보관할 수 있습니다.
- 비동기적データ 처리에 유용합니다.

ch2 := make(chan string, 2)

ch2 <- "data1" // 버퍼에 보관
ch2 <- "data2" // 버퍼에 보관

fmt.Println(<-ch2) // data1 출력
fmt.Println(<-ch2) // data2 출력  

이 외에도 닫힘 여부에 따라 닫힌 채널인지 아닌지를 확인할 수 있고, range 문을 사용하여 채널 internal의 데이터를 반복 처리할 수도 있습니다.

closed := make(chan int)
close(closed)

v, ok := <-closed
// ok는 false가 됨

for i := range ch2 {
    fmt.Println(i) 
    // ch2 internal의 데이터를 차례대로 받아 처리
}

위와 같이 고(Go)언어의 채널은 단순 데이터 통신 뿐 아니라 동기화, 병렬처리 등 다양한 용도로 활용할 수 있습니다. 버퍼의 유무와 닫힘 여부에 따라 활용법이 달라지므로 상황에 맞게 잘 활용한다면 효과적인 병렬처리가 가능합니다.

저의 설명이 도움이 되셨기를 바랍니다.

프로그램언어 고(Go)에서의 고루틴과 채널을 이용한 데이터 전송

프로그램언어 고(Go)에서 고루틴과 채널을 이용한 데이터 전송에 대해 설명드리겠습니다.

고(Go) 언어에서는 고루틴(goroutine)과 채널(channel)이라는 기능을 제공합니다. 고루틴은 가벼운 스레드라고 볼 수 있으며, 여러 고루틴을 동시에 실행할 수 있습니다. 채널은 고루틴 간에 데이터를 주고받는 통로 역할을 합니다.


package main

import "fmt"

func hello(c chan string) {
    c <- "Hello World!" // 채널 c에 "Hello World!" 문자열 보내기
}

func main() {
    c := make(chan string) // 채널 만들기
    
    go hello(c) // 고루틴에서 hello 함수 실행

    msg := <-c // 채널 c에서 데이터 받기
    fmt.Println(msg) // 받은 데이터 출력
}

위 예제코드를 살펴보겠습니다. main 함수에서 문자열을 주고받기 위한 채널 c를 만듭니다. 그리고 고루틴을 이용해 별도의 hello 함수를 비동기적으로 실행합니다.

hello 함수 내에서는 매개변수로 받은 채널 c에 "Hello World!" 문자열을 보냅니다.

다시 main 함수로 돌아와 채널 c에서 데이터를 받습니다. 그리고 받은 데이터를 출력합니다.

이러한 식으로 고루틴과 채널을 이용해 스레드간 효율적이고 안전한 데이터 전송이 가능합니다. 고루틴 실행시 주고 받을 채널을 매개변수로 연결해주기만 하면, 서로 다른 고루틴들 사이에서 데이터 전송을 쉽고 유연하게 처리할 수 있습니다.

프로그램언어 고(Go)에서의 채널을 사용한 고루틴 간의 통신

프로그램언어 고(Go)에서 채널을 사용한 고루틴 간의 통신은, 고루틴들 간에 데이터를 안전하고 동기화된 방식으로 교환할 수 있도록 해주는 매커니즘입니다.

채널은 기본적으로 큐(Queue)와 비슷한 데이터 구조를 가지고 있습니다. 한 고루틴이 채널에 데이터를 보내면 그 데이터는 채널에 저장되고, 다른 고루틴이 그 채널から 데이터를 받으면 저장된 데이터를 리턴받게 됩니다.


package main

import "fmt"

func ping(ch chan string) {
    ch <- "ping"
}

func pong(ch chan string) {
    msg := <- ch
    fmt.Println(msg)
    ch <- "pong"
}

func main() {
    var ch chan string = make(chan string)

    go ping(ch)
    go pong(ch)

    var input string
    fmt.Scanln(&input)
} 

위 예제코드를 살펴보면,
main 함수에서 문자열을 주고받을 수 있는 ch 채널을 만들고,
ping 이라는 고루틴과 pong 이라는 고루틴을 별도의 thread에서 실행합니다.

ping 함수는 ch 채널로 "ping" 이라는 문자열을 보냅니다.
pong 함수는 ch 채널로부터 문자열을 받아서(<-ch) 출력하고, 다시 "pong" 이라는 문자열을 ch 채널로 보냅니다. 이처럼 ch 채널을 통해 서로 다른 고루틴들 간에 문자열을 안전하게 전달할 수 있습니다. main 함수의 Scanln으로 대기하고 있다가 프로그램이 종료됩니다. 채널을 사용할 때는 반드시 데이터를 보내는 쪽과 받는 쪽이 모두 준비된 상태여야 합니다. 그래서 위 예제코드처럼 별도의 고루틴에서 병렬 실행을 시키는 것이 일반적입니다. 한 고루틴에서 채널로 데이터를 보내기 전에 다른 고루틴이 이미 그 채널로부터 데이터를 받으려고 대기하고 있어야 정상 작동합니다. 즉, 데이터의 송신자(sender)와 수신자(receiver)가 모두 준비된 경우에만 통신이 가능합니다. 이러한 동기화된 통신방식은 고루틴간의 경쟁상태를 방지하고 안전한 데이터 교환을 가능하게 해줍니다. 프로그램언어 고(Go)의 채널과 고루틴은 CSP(Communicating Sequential Processes) 모델의 특성을 그대로 반영하고 있다고 볼 수 있습니다.

프로그램언어 고(Go)에서의 채널을 이용한 고루틴 동기화

Go 언어의 고루틴과 채널을 이용하면 효과적으로 병행처리를 할 수 있습니다.

고루틴은 Go 언어의 가볍고 효율적인 스레드입니다. 여러 고루틴을 만들어 비동기로 병행작업을 처리할 수 있습니다.

그리고 채널은 고루틴 간에 데이터를 주고받는 통로입니다.

예를 들어 아래와 같이 producer와 consumer 고루틴을 만들고 채널을 이용해 데이터를 주고받을 수 있습니다.


package main

import "fmt"

func producer(ch chan int) {
    for i := 0; i < 10; i++ {
        ch <- i
    }
    close(ch)
}

func consumer(ch chan int) {
    for num := range ch {
        fmt.Println(num)
    }
}

func main() {
    ch := make(chan int)
    go producer(ch)
    consumer(ch)
}

producer 고루틴이 데이터를 생성해 채널에 보내고, consumer 고루틴이 채널로부터 데이터를 받아서 사용하는 구조입니다.

채널 없이 단순히 고루틴만 이용하면 데이터 경합이 발생할 수 있습니다.

하지만 채널을 사용하면 동기화가 보장되어 안전하게 데이터를 주고받을 수 있습니다.

채널로 보낸 데이터는 반드시 고루틴에서 받아가게 됩니다.

따라서 Go 언어의 채널은 고루틴 간 통신과 동기화를 위해 매우 유용하게 사용할 수 있습니다.

프로그램언어 고(Go)에서의 고루틴과 채널을 활용한 병렬처리 방법

package main

import (
    "fmt"
    "time"
)

func process(ch chan string) {
    time.Sleep(3 * time.Second) // 가상의 처리 시간
    ch <- "처리 완료"
}

func main() {
    ch := make(chan string)

    go process(ch)

    fmt.Println("기다리는 중...")
    result := <-ch
    fmt.Println(result)
}

고루틴과 채널을 사용하면 병렬 처리가 가능합니다. 위의 예제코드에서 process 함수를 고루틴으로 실행하여 별도의 처리 작업을 병렬로 수행합니다.

process 함수가 채널을 통해 "처리 완료" 문자열을 보내면 메인 고루틴이 이를 받아 결과를 출력합니다. 이렇게 채널을 사용하여 서로 다른 고루틴간 통신과 데이터 전달이 가능합니다.

고루틴을 사용하지 않으면 process 함수가 반환할 때까지 메인 함수가 기다렸다가 결과를 출력할 것입니다. 하지만 고루틴을 사용하면 process 함수를 별도로 수행시키기 때문에 메인 함수와 병렬로 작업할 수 있습니다.

즉, 고(Go) 언어의 고루틴과 채널은 병렬 처리 작업과 루틴 간 통신에 유용하게 사용됩니다. 이를 잘 활용하면 복잡한 동시성 제어 없이도 효과적으로 병렬 프로그래밍이 가능합니다.

위 설명이 도움이 되었기를 바랍니다.

Leave a Comment