들어가기에 앞서
Go를 알아보면서 병행성이 있는 건 알고 있었지만 이렇게 코드로 겪어보니 운영체제 공부할 때가 떠올라 신기하기도 하고 재밌기도 했다
병행성과 병렬성의 차이를 알고 가야될 필요가 있다 (헷갈림..)
병렬성과 병행성의 차이
병렬성은, 실제로 여러 작업을 동시에 수행하는 것을 의미한다.
병행성은, 마치 여러 일을 동시에 하듯이 수행하는 것을 의미한다.
Go 루틴이란
Go 루틴의 특징은 OS가 아닌 프로그램에서의 Time _ Sharing 처리이다
프로세스(Process)를 쓰던 스레드(Thread)를 쓰던 오버헤드가 생길 수 밖에 없다
왜냐면 우리가 컴퓨터를 쓸 때 많은 동작을 컴퓨터에게 시키기 때문이다 하나의 명령만 컴퓨터 주는 게 아니라 이것 저것 시키기 때문에 컴퓨터 안에서는 컨텍스트 스위칭(Context Switching)이 매우 많이 자주 발생한다 이는 OS에서 짜주는 방식으로 돌아간다
여기서 Go루틴이 신기한 것은 Thread를 사용하지 않는 다는 것이다
Go는 Os에 따로 Process나 Thread에게 요청하지 않는다 --> Kernel에서 활동하는 Process, Thread를 요청하지 않는 다는 것
-> 즉 Context Switching이 엄청 낮아진다 그리고 나는 Kernel (System call)안에 들어가지 않고 스케쥴링 관리를 한다면 엄청 빠르 거라고 생각한다
C에서 Multi Process, Multi Thread 코드를 각각 구현해본 적이 있는데 무척 복잡했다 각 스레드마다 프로세스 마다 Signal도 넣어줘야 하고.. 그리고 여기서 만약 Thead간 채팅 등 동기식으로 만드려면 정말 어렵다 (변수들의 값이 충돌하지는 않는지 참조하는 것이 같지는 않은지)
그래서 Go에서는 채널(Channel)을 통해 간단하게 처리해준다
Channel
위에서 말했듯이 멀티스레드에서 동기화를 진행하면 데이터를 공유하거나 실행 순서를 제어해야 하는데
쉬운일이 아니다.. 오류가 빈번하게 발생하고 하나라도 틀리면 많은 값들이 잘 못 나온다
그렇다면 Go에서는 동기화를 어떻게 진행할까?
채널(Channel)을 이용해서 통신을 처리하는데 쉽게 말해서 파이프(Pipe)라고 생각하자
위 그림에서 보듯이 양방향이다 모든 타입을 채널로 사용할 수 있다 bool, string, int.. 등등 그런데 채널 자체는 값이 아닌 래퍼런스 타입이다!!
자 그러면 이제 코드를 봅시다
package main
import (
"fmt"
"time"
)
func main() {
c := make(chan string)
for i := 0; i < 10; i++ {
go User(c)
go admin(c)
fmt.Print(<-c + " " + <-c + "\n")
time.Sleep(time.Second)
}
}
func User(c chan string) {
c <- "User"
}
func admin(c chan string) {
c <- "Admin"
}
먼저 채널인 c를 만들어 줍시다
그리고 for문을 10번 반복합니다 -> go 키워드를 멀티 스레드 처럼 사용!
이제 채널에 있는 값을 출력! Sleep()은 잘 작동하는지 확인하는 용도입니다
이렇게 진행하면 보통 main이 끝나버리면 go루틴도 자동 종료되지만 <-c를 출력함으로써 값을 받아올 때 까지는 멈추지 않도록 설정해줬습니다
밑에는 결과값입니다
질문은 또는 틀린게 있다면 댓글 부탁드립니다!!
참고한 자료
'Go' 카테고리의 다른 글
[Go] Go로 로그 패키지 만들기 (1) (1) | 2023.03.07 |
---|---|
[Go] golang slice안에 특징 (0) | 2023.02.16 |
[Go] struct를 생성하고 error코드 작성하기 (0) | 2023.01.09 |
[Go] append와 가비지 컬렉터의 관계 & if, switch문 알아보기 (0) | 2023.01.09 |
[Go] $GOPATH/go.mod exists but should not 오류 (0) | 2023.01.09 |