18.1. 프로그램언어 고(Go)의 고루틴 생성과 관리

프로그램언어 고(Go)에서의 고루틴 초기화 및 실행

프로그램언어 고(Go)에서 고루틴을 초기화하고 실행하는 방법에 대해 설명드리겠습니다.

package main

import (
    "fmt"
    "time"
)

func process(ch chan string) {
    time.Sleep(3 * time.Second) // 3초 대기
    ch <- "processed" // channel에 "processed" 보내기 
}

func main() {
    ch := make(chan string) // channel 생성

    go process(ch) // 고루틴에서 process 함수 실행

    fmt.Println("Waiting...")
    res := <-ch // channel에서 receive 하여 res 변수에 할당
    fmt.Println(res)
}

위 예제코드에서 보다시피, 고루틴은 go 키워드를 사용하여 실행합니다.

go process(ch)와 같이 함수 앞에 go를 붙이면 해당 함수가 고루틴 내에서 비동기적으로 실행됩니다.

이로써 함수의 실행이 메인 고루틴을 막지 않고 병렬로 수행될 수 있습니다.

process 함수에서는 3초 sleep 후 채널에 "processed" 문자열을 보냅니다.

메인 고루틴에서는 고루틴 실행 후 채널로부터 메시지를 받아 출력하는 등 동작을 병렬로 처리합니다.

채널(channel)은 고루틴 간 통신을 위한 수단으로, make 함수로 초기화합니다.

고루틴은 leightweight한 스레드와 같은 의미로, 코드의 병렬 실행을 가능케 합니다.

이를 통해 I/O 대기시간이나 병렬 처리 시간을 줄일 수 있습니다.

위 예제와 같이 고루틴+채널을 적절히 활용하면 동시성 프로그래밍을 효과적으로 할 수 있습니다.

프로그램언어 고(Go)에서의 고루틴 상태 확인

고루틴은 GO 언어의 가장 큰 특징 중 하나입니다. 고루틴을 사용하면 쉽게 병렬 처리가 가능한 비동기 함수를 만들 수 있습니다.

고루틴의 상태를 확인하는 것은 고루틴을 제대로 사용하기 위해 아주 중요합니다. 주로 다음과 같은 방법들이 사용됩니다.


func printGoRoutineNum() {
  fmt.Println("Current goroutine num: ", runtime.NumGoroutine()) 
}

runtime 패키지의 NumGoroutine() 함수를 사용하면 현재 실행중인 고루틴의 개수를 쉽게 알 수 있습니다.


func main() {
  go printGoRoutineNum()
  go printGoRoutineNum()
  
  time.Sleep(1 * time.Second)
  
  printGoRoutineNum()
}

이 예제에서 main 고루틴 외에 두 개의 고루틴이 추가로 만들어졌습니다.
Sleep 을 주어 다른 고루틴들이 실행될 시간을 준 후, 현재 고루틴 개수를 출력했습니다.

  
func main() {

  c1 := make(chan string)
  c2 := make(chan string)

  go func() {
    time.Sleep(1 * time.Second)
    c1 <- "one"
  }()

  go func() {
    time.Sleep(2 * time.Second) 
    c2 <- "two"
  }()

  for i := 0; i < 2; i++ {
    select {
    case msg1 := <-c1:
      fmt.Println("received", msg1)
    case msg2 := <-c2:
      fmt.Println("received", msg2)
    }
  }
}

여기서 select문을 사용하여 channel로부터 메시지를 기다리면서 고루틴의 실행을 대기합니다. 즉, main 고루틴이 다른 고루틴들의 작업이 끝날 때까지 기다리도록 구현한 것입니다.

이런 방법으로 고루틴의 작업 완료를 확인하고 동기화를 맞출 수 있습니다.

고루틴의 상태를 제대로 파악하고 관리하는 것이 중요합니다.
위의 예제들을 참고하셔서 고루틴의 실행 흐름을 명확히 하고, 문제없이 프로그램을 작성하시기 바랍니다.

프로그램언어 고(Go)에서의 고루틴 종료 처리

프로그램언어 고(Go)에서 고루틴은 병행성을 위한 가벼운 스레드와 비슷한 개념입니다. 고루틴을 사용하면 병렬 처리가 가능합니다.

고루틴을 종료하는 처리는 중요합니다. 왜냐하면 사용되지 않는 고루틴이 메모리를 차지하고 있기 때문입니다. 주로 다음과 같은 방법으로 고루틴을 종료합니다.

package main

import (  
    "fmt"
    "time"
)

func process(ch chan bool) {
    for {
        fmt.Println("고루틴 실행 중")
        time.Sleep(1 * time.Second) 
    }
}

func main() {

    ch := make(chan bool)

    go process(ch)

    time.Sleep(5 * time.Second)
    
    close(ch) // ch 채널을 닫음

    time.Sleep(2 * time.Second)  
}

예제에서는 고루틴 내부의 무한 루프에서 채널(ch)을 확인합니다.

main 함수에서는 5초 후에 해당 채널을 close 해주면, 고루틴 내부의 for문을 종료시킵니다.

즉, 채널을 close하는 것으로 고루틴을 종료할 수 있습니다.

다만, 이 경우에는 고루틴이 종료되는 것을 보장하지 않습니다. 정확히는 close된 채널에서 값을 읽으려고 하면 기본값을 반환하고 for문이 종료됩니다.

따라서 고루틴 내부에서 채널 상태를 확인하는 로직이 추가되어야 합니다.

package main

import (
    "fmt"
    "time"
)

func process(ch chan bool) {
    for {
       if _, opened := <-ch; !opened {
           fmt.Println("채널 닫힘 확인됨. 고루틴 종료")  
           break
       }

       fmt.Println("고루틴 실행 중")  
       time.Sleep(1 * time.Second)
    }
}

func main() {

    ch := make(chan bool)

    go process(ch)

    time.Sleep(5 * time.Second)
    
    close(ch)

    time.Sleep(5 * time.Second)  
}

위의 예제코드와 같이 채널이 닫혔는지 확인하는 로직을 추가하면 정상적으로 고루틴을 종료시킬 수 있습니다.

채널 외에도 WaitGroup을 사용하거나, context를 사용하는 방법도 있습니다.

WaitForGroup을 사용하면 고루틴이 종료될 때까지 기다릴 수 있고, Context를 사용하면 타임아웃까지 설정할 수 있어 보다 정교한 고루틴 종료 처리가 가능합니다.

이 정도로 프로그램언어 고(Go)의 고루틴 종료 처리에 대한 주요 내용을 설명 드렸습니다. 예제코드와 함께 이해하기 쉽도록 설명드렸으니 참고해 주시기 바랍니다.

프로그램언어 고(Go)에서의 고루틴 우선순위 관리

Go 언어의 고루틴은 경량 스레드와 비슷한 개념으로, 동시에 실행할 수 있는 함수들입니다. 고루틴은 우선순위에 따라 실행되며, 이를 효과적으로 관리하는 것이 중요합니다.

고루틴의 우선순위는 정수값으로 표현되며, 값이 높을수록 우선순위가 높다고 볼 수 있습니다. Go运行时会根据优先级的值选择下一个执行的goroutine。默认情况下,每个고루틴의 우선순위는 0으로 설정됩니다.


package main

import (
    "fmt"
    "time"
)

func task(name string, priority int) {
    for i := 1; true; i++ {
        fmt.Printf("[%s] 출력: %d\n", name, i)
        time.Sleep(100 * time.Millisecond) 
    }
}

func main() {

    // 기본 우선순위 0
    go task("goroutine 1", 0)  

    // 우선순위 설정
    go task("goroutine 2", 1)

    // 무한루프
    select{}  
}

위 예제코드에서 goroutine 1과 goroutine 2가 동시에 실행됩니다. 여기서 goroutine 2의 우선순위를 1로 지정했기 때문에, goroutine 2가 항상 goroutine 1보다 먼저 실행됨을 확인할 수 있습니다.

고루틴의 우선순위는 runtime.Goexit() 함수를 사용하여 동적으로 변경할 수도 있습니다.


package main

import (
    "runtime"
    "fmt"
)

func task() {

    for i := 1; i <= 5; i++ {
        runtime.Gosched() 
        fmt.Println("A:", i)
    }
}

func task2() {
    
    for i := 1; i <= 5; i++ {
        runtime.Goexit()
        fmt.Println("B:", i)
    }
}

func main() {  
    // 고루틴 생성
    go task()  
    go task2()

    // 무한 대기
    for {} 
}

위 예제에서 task() 고루틴은 기본 우선순위인 0을 가집니다. 하지만 task2() 고루틴 내에서 Goexit()를 호출하여 우선순위를 1로 올리고 있습니다.

결과적으로 task2()가 항상 먼저 출력되는 것을 확인할 수 있습니다. 이와 같이 Goexit()를 사용하여 동적으로 우선순위를 조정할 수 있습니다.

이 외에도 고루틴 풀(Goroutine Pool)을 만들어 우선순위 큐로 관리하는 방법도 있습니다. 풀에 있는 고루틴만 실행할 수 있도록 제한하고 우선순위에 맞게 실행순서를 정리하는 것입니다.

이를 통해 보다 체계적인 우선순위 기반의 고루틴 실행 관리가 가능합니다.

프로그램언어 고(Go)에서의 대용량 고루틴 관리

프로그램언어 고(Go)에서 대용량 고루틴을 관리하는 방법에 대해 설명드리겠습니다.

고루틴은 Go 언어의 가장 큰 특징 중 하나로, 비동기 작업을 위한 경량 스레드로 활용됩니다. 대용량 고루틴을 사용하면 병렬 처리 능력이 뛰어나지만 동시에 메모리와 CPU 사용량이 많이 소모되기 때문에 이를 효율적으로 관리할 필요가 있습니다.


package main

import (
    "fmt"
    "runtime"
    "sync"
)

func main() {

    var wg sync.WaitGroup

    // 고루틴 개수 설정
    numRoutines := 1000

    // 고루틴 풀 생성
    p := make(chan int, numRoutines)

    wg.Add(numRoutines)

    for i := 0; i < numRoutines; i++ {
        go func() {
            // 고루틴 로직
            fmt.Println("Hello")
            
            wg.Done()
        }(p)
    }

    wg.Wait()

}

위 예제코드에서 볼 수 있듯이, 대용량 고루틴을 생성할 때에는 고루틴 풀(p)을 만들어 제한을 두는 것이 좋습니다. 풀의 크기를 고루틴 개수와 동일하게 설정하면 동시 실행 가능한 고루틴 개수를 제한할 수 있습니다.

또한 WaitGroup을 사용하여 모든 고루틴이 종료될 때까지 기다리도록 처리할 수 있습니다. 이러한 방식으로 고루틴의 병렬 처리를 유지하면서도 리소스 사용량을 효율적으로 관리할 수 있습니다.

아울러 고루틴이 끝날 때마다 풀에 값을 다시 반환하도록 하면 해당 슬롯을 재사용할 수 있기 때문에 고루틴 풀의 크기를 실제 필요한 것보다 작게 유지할 수도 있습니다.

이 외에도 고루틴 개수 및 사용량을 직접 모니터링하거나, 점진적으로 늘려가며 테스트하는 등 다양한 방법으로 대용량 고루틴을 관리할 수 있습니다.

프로그램언어 고(Go)에서의 대용량 고루틴 관리 방법에 대해 간략히 설명드렸습니다. 보다 자세한 내용은 공식 문서나 관련 서적을 참고하시기 바랍니다.

Leave a Comment