Backend/GoLang

[Golang] Channel 과 비동기 메커니즘의 GoRoutine을 알아보자!

Juwon2106 2022. 2. 5. 21:46
728x90

go routines

이번 포스팅에서 알아볼 내용으로는

GoRoutine과

Channel에 대해

간단히 알아보겠습니다.

 

GoRoutine이란??

GoRoutine은 Go Runtime이 관리하는 논리적 혹은 가상적 Thread입니다.

 

Go에서 go 키워드를 사용하여 함수를 호출하면, 런타임 동안 새로운 goroutine을 실행합니다.

 

goroutine은 비동기적으로( asynchronously ) 함수를 실행하며 여러 코드를 동시에( Concurrently ) 실행하는 기능입니다.

 

또한, Goroutine은 함수 및 메소드를 다른 함수 및 메소드와 동시에( 병렬형 ) 사용 가능하게 하는 기능입니다.

 

GoRoutine은 OS Thread에 비해 엄청난 경량 Thread입니다. ( OS Thread : 1MB, GoRoutine : 2kb )

 

Go 런타임 상에서 관리되는 여러 goroutine들은 종종 하나의 OS Thread로 실행되고는 합니다.

 

즉 GoRoutine은 OS Thread와 1대1로 매칭되지 않고 Multiplexing으로 훨씬 적은 OS Thread를 사용합니다.

 

Channel

Channel이란??

 

Go Channel은 해당 Channel을 통해 GoRoutine과 Goroutine 혹은 Main 함수 서로의 데이터를 주고받는 파이프 통로 입니다.

 

Channel은 make() 함수를 통해 미리 생성해야하며 채널 연산자 ( <- )를 통해 데이터를 보내고 받을 수 있습니다.

 

Channel은 상대편이 준비될 때까지 채널에서 대기하며 별도의 lock을 걸지 않고 데이터를 동기화 하는데 사용됩니다.

 

Channel로 데이터를 보낼때는

 

channel 변수명 <- data 와 같이 사용하고

 

데이터를 받을 때에는

 

<- channel 변수명으로 사용합니다.

 

다음은 http.Get() 함수를 사용한 예제입니다.

package main

import (
	"errors"
	"fmt"
	"net/http"
)

type requestResults struct {
	url    string
	status string
}

var errRequestFailed = errors.New("Request failed")

// functional programing
func main() {
	// map이 초기화가 안되서 에러
	// var requestResultss map[string]string

	// make() 함수로 초기화
	var results = make(map[string]string)
	c := make(chan requestResults)

	urls := []string{
		"https://www.airbnb.com/",
		"https://www.google.com/",
		"https://www.amazon.com/",
		"https://www.reddit.com/",
		"https://www.google.com/",
		"https://soundcloud.com/",
		"https://www.facebook.com/",
		"https://www.instagram.com/",
	}

	for _, url := range urls {
		go hitURL(url, c)
	}
	for i := 0; i < len(urls); i++ {
		// fmt.Println(<-c)
		result := <-c
		results[result.url] = result.status
	}
	for url, status := range results {
		fmt.Println(url, status)
	}

}

func hitURL(url string, c chan<- requestResults) {
	resp, err := http.Get(url)
	status := "OK"
	if err != nil || resp.StatusCode >= 400 {
		status = "FAILED"
	}
	c <- requestResults{url: url, status: status}
}

결과 화면

urls Slice의 인덱스 순서와 관계없이 병렬형으로 결과값을 받는 것을 확인할 수 있습니다.

 

2개의 GoRoutine으로 데이터를 보낼 때

 

3개 이상으로 데이터를 받으면

 

fatal error : all goroutines are asleep - deadlcok! 예외가 발생합니다.

 

또한 main함수가 종료되지 않고 GoRoutine이 Channel을 통해 메세지를 받기 전까지 Main 함수를 멈추는 것을

 

Blocking Operation이라고 합니다.

 

이번 포스팅으로 GoRoutine과 Channel에 대해 알아보았습니다.

728x90