한 눈에 끝내는 고랭 기초
    • 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)
      최종 코드
    채널 닫기
    18 채널(Channel)
    채널 닫기

    루틴에서 채널을 생성하고 데이터를 송신하기 위해서는 수신하는 곳이 명확해야 합니다. 동기 채널에서는 수신 루틴(다른 루틴이어야 함)에서, 비동기 채널에서는 버퍼에서 데이터를 수신합니다. 만약 수신하는 곳이 명확하지 않은 채 채널로 데이터를 송신한다면 채널에 묶여 무한 대기 상황이 발생합니다. 메인 루틴에서 무한 대기 상황이 발생하면 데드락이 발생합니다.

    데이터 수신시에도 마찬가지로 송신된 데이터가 없을 경우에 채널에서 데이터를 수신하면 무한 대기 상태가 됩니다. 그런데 이때 채널에 데이터를 송신한 후 채널을 닫으면 해당 채널로는 더이상 데이터를 송신할 수 없지만 채널이 닫힌 후에 계속 수신이 가능하게 됩니다. 채널을 닫을 때는 "close(채널이름)" 형식을 사용합니다.


    아래 첫 번째 예시 코드는 송신자보다 수신자가 많은데 채널을 닫지 않아 데드락이 발생하고, 두 번째 예시 코드는 송신자보다 수신자가 많지만 송신 후에 채널을 닫아 계속 송신해도 오류가 발생하지 않습니다. 바로 실행해보세요.

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

    위 첫 번째 예시는 송신자는 두 개인데, 수신자를 세 개로 설정하여 세 번째 수신자에서 무한 대기 상황이 발생합니다. 이에 반해 두 번째 예시는 채널에 송신하고 채널을 닫았기 때문에 그 이후에 몇개의 수신자를 입력하든 대기하지 않습니다. 두 번째 수신자까지는 채널(버퍼)의 값을 수신하고 세 번째 수신자부터는 nil 값을 반환합니다.

    이렇게 데이터를 모두 송신하고 채널을 닫으면 무한 대기 상황을 미연에 방지할 수 있습니다. 그리고 채널을 닫을 때 두 가지 특징이 있습니다.

    • 채널을 닫은 후에 데이터를 채널에 송신하면 'send on closed channel' 라는 메시지와 함께 panic이 발생한다.
    • 채널의 데이터를 모두 수신하고 또 수신하면 nil 값을 반환합니다.

    그리고 추가적으로 채널의 특징이 있습니다.

    • 수신자를 의미하는 "<- 채널이름"은 두 개의 값을 반환합니다. 첫 번째는 채널 데이터, 두 번째는 채널의 개폐 여부를 알려주는 true/false 값입니다. 채널이 열려있다면 'true', 닫혀있다면 'false'를 반환합니다.


    아래 수신자가 반환하는 두 값을 출력해보는 예시가 있습니다. 바로 실행해보세요.

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

    채널 range문


    range는 반복문을 사용할때 for range문으로 사용했습니다. '반복문' 챕터에서는 for문에 반복 횟수를 따로 설정하지 않고 컬렉션의 요소 개수만큼 반복해 접근하는 기능을 했습니다. 이와 마찬가지로 채널에서의 range문은 채널의 데이터를 채널에 송신한 데이터의 개수만큼 접근하는 용법입니다. 이때, 주의할 점은 range는 송신 채널이 닫히지 않았다면 데이터가 들어올 때까지 계속 대기하기 때문에 데이터가 들어올 때마다 계속 접근(데이터를 수신)합니다. 따라서 range문은 닫힌 채널의 데이터를 수신할 때 사용하는 것이 일반적입니다. 당연히 열린 채널에 range문을 main() 함수에 사용하면 데드락이 발생하게 되겠죠?


    우선, 위에서 소개한 range문을 활용해보기 전에 직관적인 방법으로 수신자의 두 번째 반환값인 'ture/false'를 이용해 채널의 데이터를 모두 접근하는 예시 코드를 바로 실행해보세요.

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

    위 코드는 open이 'false'가 됐을 때만 break로 반복문을 빠져나갈 수 있습니다. 즉, 채널에 데이터를 송신 후 닫지 않으면 if val, open := <-c; open 부분에서 open이 계속 'true'이기 때문에 데드락이 발생합니다.


    이제 range문을 활용해 위 코드를 수정해보겠습니다. 바로 실행해보세요.

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

    range문을 사용하면 반복문에서 따로 횟수를 설정하지 않아도 채널의 모든 데이터를 접근합니다. 주의할 점은 for val := range c{처럼  채널 수신자인 '<- c' 를 사용하는 것이 아니라 채널 이름 c만 range문에 사용합니다. 

    질문하기