Go 언어 시작기 #4

ims·2021년 6월 21일
0

GO 언어 시작기

목록 보기
4/4

📌 Go routine

비동기 프로그래밍을 아주 간단하게 구현할 수 있게 제공하는 기능

  • 단, go routine은 main 함수가 끝나지 않을 때에만 의미가 있다.

  • Main 함수는 go routine을 기다려주지 않는다.

package main

import (
	"fmt"
	"time"
)

func main() {
	go printMember("ersu")
	printMember("heechan")
}

func printMember(name string){
	for i:=0; i<4; i++{
		fmt.Println(name,i)
		time.Sleep(time.Second)
	}
}

위 코드는 아래와 같이 동작한다.

go printMember("ersu")

parameter를 ersu로 넘기는 함수에 go를 붙이면 아래와 같이 비동기적으로 작동한다.

func main() {
	go printMember("ersu")
	go printMember("heechan")
}

그러나 위와 같이 두 함수 모두에 go를 붙여버리면 아무것도 출력하지 않고 그냥 함수가 끝나버리는데, 이것은 main함수는 go routine을 기다려주지 않기 때문이다.

func main() {
	go printMember("ersu")
	go printMember("heechan")
	time.Sleep(time.Second*2)
}

만약 main 함수에 2초라는 시간을 준다면, 2초만큼만 출력하게 된다.

📌 Channel

GO ROUTINE과 Main Function 사이에 정보를 전달하기 위한 방법
GO ROUTINE에서 다른 GO ROUTINE으로 가는 것도 가능하다

즉, GO ROUTINE 사이에 어떻게 커뮤니케이션을 하는 가에 대한 이야기

package main

import "time"

func main() {
	people := [2]string{"얼쑤","희찬"}

	for _, person := range people{
		go isSexy(person)
	}
}

func isSexy(person string) bool{
	time.Sleep(time.Second*3)
	return true
}

Golang은 go routine의 return 값을 직접적으로 받을 수 없다.

예를 들어 아래와 같이 값을 받을 수 없다는 말이다.

returnValue = go isSexy()

그렇다면 go routine의 값은 어떻게 받아야 하는가?
이 때, Channel이 등장한다.


🔥 Channel 생성

func main() {
	channel := make(chan bool)
...

뒤에 bool인 것은, channel이 받을 return type이 boolean값인 것을 알려주는 것이다.

func isSexy(person string, channel chan bool) {
	fmt.Println(person)
	time.Sleep(time.Second*3)
	channel <- true
}

function의 return value를 받기 위해, parameter로 chan type을 받는다.

return value는 사라지고, 해당 channel에 true값을 반환한다고 명시해준다.

🔥 Channel version1)

func main() {
	channel := make(chan bool)
	people := [2]string{"얼쑤","희찬"}

	for _, person := range people{
		go isSexy(person, channel)
	}
	result := <-channel
	fmt.Println(result)
}

func isSexy(person string, channel chan bool) {
	fmt.Println(person)
	time.Sleep(time.Second*3)
	channel<-true
}

재밌는 점은, true가 한번만 출력됐다는 것이다. 이것은 채널로부터 뭔가를 받을 때, 메인 함수는 어떤 답이 올 때까지 기다린다.

result := <-channel

golang은 위의 메세지를 보고, 멈춰서서 메세지를 하나 받을 때까지 멈춰선다.
위 코드는 아래 코드와 동치다.

fmt.Println(<-channel)

channel 을 2개 보내면 2개가 true가 찍힌다.

그렇다면, 3개를 찍어보면 어떻게 될까?

func main() {
	channel := make(chan bool)
	people := [2]string{"얼쑤","희찬"}

	for _, person := range people{
		go isSexy(person, channel)
	}
	fmt.Println(<-channel)
	fmt.Println(<-channel)
	fmt.Println(<-channel)
}

deadlock에 걸린다. 만약 배열의 크기를 3개로 정하면 다시 정상적으로 true가 3개 출력되는 것을 볼 수 있다.

go routine은 해당 range에 따라 go routine 수를 할당해놓는다. 그래서 할당된 go routine보다 많은 go routine이 할당되면 deadlock에 걸린다.

🔥 Channel version 2)

Channel은 blocking operation 이다.

즉, result 값을 받을 때까지 기다린다.

func main() {
	channel := make(chan string)
	people := [6]string{"얼쑤","희찬","규헌","종원","아이돌","강아지"}

	for _, person := range people{
		go isSexy(person, channel)
	}

	result1 := <- channel
	result2 := <- channel
	result3 := <- channel

	fmt.Println(result1)
	fmt.Println(result2)
	fmt.Println(result3)

}

func isSexy(person string, channel chan string) {
	time.Sleep(time.Second*3)
	channel<- person + " is sexy"
}

channel로부터 값을 받은 순서대로 값을 출력할 수 있다. 실행은 병렬적으로 되므로, 어떤 값을 먼저 받을 지는 알 수 없다.

func main() {
	channel := make(chan string)
	people := [6]string{"얼쑤","희찬","규헌","종원","아이돌","강아지"}

	for _, person := range people{
		go isSexy(person, channel)
	}
	for i:=0 ; i<len(people); i++{
		fmt.Println(<-channel)
	}
}

func isSexy(person string, channel chan string) {
	time.Sleep(time.Second*3)
	channel<- person + " is sexy"
}

매번 <- opertion을 쓰지 않고, loop를 돌리면 n회 작업을 처리할 수 있다.

profile
티스토리로 이사했습니다! https://imsfromseoul.tistory.com/ + https://camel-man-ims.tistory.com/

0개의 댓글