한 눈에 끝내는 고랭 기초
    • 01
      시작하기에 앞서
    • 강의대상
      Go란?
      실습 환경 구축 - 구름IDE
      Hello goorm! 출력해보기
    • 02
      변수와 상수
    • 콘솔 출력 함수의 기본
      변수의 선언과 초기화
      상수의 선언과 초기화
      간단한 덧셈
      잘못된 신상정보
    • 03
      연산자
    • 연산자 종류
      연산자 우선순위
      콘솔 입력 함수의 기본
      간단한 덧셈과 곱셈
      몫과 나머지
    • 04
      자료형
    • 자료형의 종류와 특징
      문자열의 표현
      자료형의 변환
      강제 형 변환
    • 05
      콘솔 출력과 입력 함수
    • 콘솔 출력 함수(Print)
      콘솔 입력 함수(Scan)
      정돈된 표
      신상정보 입력과 출력
    • 06
      반복문 - for
    • 오로지 for
      구구단
      빛나는 이등변삼각형
    • 07
      조건문 - if/else
    • 조건에 따른 실행과 흐름 분기
      7과 9의 배수
      두 수의 차
    • 08
      분기문 - switch
    • swich문에 의한 선택적 실행
      안좋은 계산기
    • 09
      제어문
    • break, continue, goto문
      구구단2
      두 수를 더하면 99
    • 10
      컬렉션
    • 배열(Array)
      슬라이스(Slice)
      맵(Map)
      역행렬
      가장 긴 이름
      중간고사 평균 점수
    • 11
      함수
    • Go언어에서의 함수
      전역변수와 지역변수
      매개변수
      반환값(리턴값)
      익명 함수
      오름차순 정렬
      아이패드를 사주는 조건
      역학적 에너지
    • 12
      클로저
    • 외부 변수 접근 : 클로저
      동전 정리
    • 13
      구조체와 메소드
    • 구조체
      메소드
      성적 저장 프로그램
      역학적 에너지2
    • 14
      인터페이스(interface)
    • 메소드의 집합 인터페이스
      직육면체와 원기둥
    • 15
      defer와 panic()
    • 지연 처리 defer
      종료하는 panic(), 복구하는 recover()
      엘리베이터
      중간고사 평균 점수2
    • 16
      에러 처리
    • 에러 처리의 기본
      에러 출력 및 처리
      중간고사 평균 점수3
    • 17
      고루틴(Goroutine)
    • 비동기 프로세스의 기본
      고루틴의 활용
      고루틴 실습
    • 18
      채널(Channel)
    • 고루틴의 데이터 통로 : 채널
      비동기 채널과 버퍼
      동기 채널
      채널 닫기
      송신 전용, 수신 전용 채널
      채널 select문
      고루틴 실습2
      메시지 전송
      동기 채널 실습
      비동기 채널 실습
    • 19
      패키지(package)
    • 패키지의 개념
    • 20
      실전 프로젝트 - 마일리지 상점
    • 프로젝트를 시작하기 앞서
      실습모드에서 실습
      마일리지 상점의 주요 기능
      필수 구조체와 매인 메뉴
      잔여 수량, 잔여 포인트 구현
    • 21
      실전 프로젝트 - 주문하기, 장바구니 담기
    • 구매 구현(1)
      구매 구현(2)
      장바구니에 담기
      장바구니 확인(1)
      장바구니 확인(2)
    • 22
      실전 프로젝트 - 고루틴으로 배송하기
    • 배송 상태 확인(1)
      배송 상태 확인(2)
      배송 상태 확인(3)
      최종 코드
    고루틴의 활용
    17 고루틴(Goroutine)
    고루틴의 활용

    이전 강의에서 main() 함수 내에 고루틴으로 실행되는 함수들이 비동기적으로 호출될때 main() 함수가 먼저 종료되는 것을 막기 위해 fmt.Scanln() 함수를 사용해 고루틴이 모두 끝날 때까지 대기하도록 했습니다. 이는 어떻게 보면 굉장히 주먹구구식 대처입니다. 원래는 고루틴이 모두 끝날 때까지 대기하는 기능이 따로 있습니다. 바로 "sync" 패키지의 WaitGroup입니다.

    WaitGroup은 "sync" 패키지에 선언되어있는 구조체로서 고루틴이 완료될 때까지 대기합니다. 이를 변수로 선언해 메소드를 활용할 수 있습니다.

    • Add() : 기다릴 고루틴의 수 설정
    • Done() : 고루틴이 실행된 함수 내에서 호출함으로써 함수 호출이 완료됐음을 알림
    • Wait() : 고루틴이 모두 끝날 때까지 차단

    지난 강의에서 실행해본 예시 코드를 WaitGroup을 이용해 만들어보겠습니다. 흐름을 잘 살펴보세요.

    go
    실행 결과를 확인해보세요!

    위 예시 코드를 보면 WaitGroup 생성 - 고루틴 개수 설정 - 끝났음을 전달 - 모두 끝날 때까지 대기(비동기라 같이 진행됨) - 종료 순서로 진행됩니다. 

    main() 함수에서 new 키워드를 사용해 WaitGroup의 wait 포인터 변수를 생성합니다.

    new 키워드로 선언한 변수는 포인터형입니다. 따라서 매개변수로 사용할 때 & 연산자를 사용하지 않아도 자동으로 주소를 참조합니다. 일반적으로 var wait sync.WaitGroup 형식으로도 선언 가능하지만 이는 그냥 변수이므로 함수의 매개변수로 전달할 때는 주소를 참조하기 위해 & 연산자를 사용해야합니다.

    그런데 그리고 wait.Add(100) 메소드를 호출해 고루틴 100개를 기다리도록 합니다. 여기서 중요한 것은 wait은 포인터 변수이기 때문에 매개변수형을 *sync.WaitGroup 형식으로 선언한 것입니다. 만약 * 연산자를 넣지 않으면 hello() 함수 내에 wmain() 함수의 wait이 다르게 인식되어(call by value) 고루틴이 모두 종료되지 않고 교착상태에 빠지게 됩니다.(Deadlock) 따라서 Call by reference 형식으로 함수 내에서 w.Done() 메소드를 호출하고 고루틴이 모두 종료됐으면 main() 함수에서 호출되어 기다리고있던 wait.Wait() 메소드도 대기를 멈추고 종료합니다.


    클로저에서의 고루틴


    사실 WaitGroup은 클로저에서 많이 활용됩니다. 위 예시를 보았다시피 wait 변수를 포인터 변수로 선언해 사용하면서 좀 복잡했습니다. 익명함수 클로저를 사용하면 클로저를 감싸고있는 함수 내에 선언된 wait을 직접 접근할 수 있기때문에 사용하기 편리합니다.

    아래 예시로 잊고있었던 클로저의 개념을 다시 복습하고 이를 이용한 wait 변수의 직접 접근을 확인해봅니다. 

    go

    일부러 string형 변수 str을 선언하고 클로저에서 직접 접근할 수 있음을 먼저 보여줬습니다. 마찬가지로 반복문 안에 defer wait.Done()wait의 메소드를 호출할 수 있습니다.


    다중 CPU 병렬 처리


    고루틴을 사용하면 고루틴에서 실행되는 함수가 비동기 처리가 된다고 했습니다. 그리고 고루틴을 아무리 많이 만들어도 한 개의 CPU에서 시분할 처리합니다. 그런데 요즘 디바이스들은 CPU가 복수개(듀얼 코어 이상)이기 때문에 Go 언어는 고루틴 뿐만이 아니라 다중 CPU를 이용한 병렬 처리를 지원합니다. 고루틴에서의 동시성(Concurrency)은 독립적으로 실행되는 기능들이고, 다중 CPU의 병렬 처리(Parallelism)는 계산들을 동시 실행하는 것입니다. 동시성은 한 번에 많은 것들을 처리하고, 병렬 처리는 한 번에 많은 일을 하는 것에 관한 것입니다.

    예를 들어, K리그를 인터넷 스트리밍으로 시청한다고 생각해봅시다. 그런데 같은 시간에 10개의 경기가 열려서(그럴 일은 없지만) 모두 시청하기 위해 10개의 창을 띄워놓고 모두 봤습니다. 이걸 바로 동시성이라고 합니다. 서로 독립된 각각의 기능들이 동시에 처리되는 것입니다. 그런데 1개의 인터넷 스트리밍은 여러가지 일들 실행됩니다. 예를 들어, 영상을 서버에서 가져오고, 사람들의 채팅 정보도 가져와야하는 등등의 일을 합니다. 이를 독립적인 CPU에서 각각의 일을 할당받아 수행하는 것을 병렬 처리라고 합니다. 

    이렇게 개념은 조금 헷갈릴 수 있어도 Go언어에서 다중 CPU를 사용하는 것은 굉장히 간단합니다. "runtime" 패키지에서 제공하는 함수를 이용하면 됩니다.

    • runtime.NumCPU() : 현재 디바이스의 CPU 개수를 반환
    • runtime.GOMAXPROCS() : 입력한 수만큼 (Logical)CPU 사용, 입력한 수가 1 미만일 때 현재 설정 값을 반환하고 설정 값은 바꾸지 않음


    위 코드에 다중 CPU를 사용해본 예시 코드를 바로 실행해보세요.

    go
    실행 결과를 확인해보세요!
    질문하기