이 글은 골든래빗 《Tucker의 Go 언어 프로그래밍》의 25~6장 써머리입니다.
이전에는 Golang의 삼신기 중 goroutine을 알아봤고 이제 남은 두 개에 대해 알아볼 차례이다. channel과 select인데 25 챕터에는 context도 포함돼 있다. 26 챕터는 지금까지 배운 내용을 사용해 단어 검색 프로그램을 만든다.
- 25 채널과 컨텍스트
- 25.1 채널 사용하기
- 25.2 컨텍스트 사용하기
- 26 단어 검색 프로그램 만들기
- 26.1 해법
- 26.2 사전지식
- 26.3 실행 인수 읽고 파일 목록 가져오기
- 26.4 파일을 열어서 라인 읽기
- 26.5 파일 검색 프로그램 완성하기
- 26.6 개선하기
25 채널과 컨텍스트
본인 경우에는 Golang에서 처음으로 멀티스레딩 코딩을 해봤다. 그래서 채널과 셀렉트 없이 어떻게 다른 언어에서 멀티스레딩을 구현하는지 모르기 때문에 비교하며 설명하지는 못한다.
1. 채널 사용하기
채널은 여러 서브루틴끼리 통신할 때 사용하기 좋은 메시지 큐이다. 큐이기 때문에 FIFO이고 채널에는 버퍼라는 개념이 있다. 버퍼는 채널의 큐에 저장할 수 있는 데이터의 양을 뜻하는데 채널을 생성할 때 크기를 명시할 수 있다. 채널을 생성할 때 크기를 명시하지 않으면 데이터를 바로 꺼내야 하기 때문에 프로그램 목적에 맞게 응용할 수 있어 좋은 것 같다.
<-, -> 연산자로 채널에 데이터를 넣고 뺄 수 있다.
이론은 여기까지고 코드로 보면
위 예제 코드를 보면 noBufferChannel과 bufferChannel이 있는데 빌드 후 실행해 보면 가끔 2번 루틴이 프린트가 안 되는 것을 볼 수 있다. 그 이유는 pushMsg 함수에서 buff에 데이터를 넣는 과정에서 noBufferChannel은 넣은 데이터를 빼줄 때까지 데이터를 못 넣는다. 반면 bufferChannel은 채널의 크기인 10만큼 계속 넣을 수 있어서 프린트가 되지 않아도 wg.Done이 호출되기 때문에 noBufferChannel이 10번 출력되면 bufferChannel의 출력을 기다려주지 않기 때문이다.
예제 코드를 select절을 이용해 변경해 보겠다.
위 예제 코드처럼 select 절을 사용하면 고루틴도 절약할 수도 있고 sync.WaitGroup도 굳이 쓸 필요 없이 작업을 끝낼 수 있다.
2. 컨텍스트
본인은 사실 컨텍스트를 사용해 본 기억이 라이브러리 쓰다 넣으라 해서 넣은 기억만 있다. 근데 책을 읽다 보니 좋은 것 같기도? 굳이 써야 하나?라는 생각도 든다. 근데 지금은 안 쓸 뜻 ㅋ
간단하게 설명하자면 고루틴을 생성할 때 컨텍스트를 통해 데이터를 넣어주거나 고루틴이 특정 시간만큼 작업하기 원하는 상황에 쓸 것 같다. 예를 들어 함수를 테스트할 때 2분 안에 끝내도록 만들어야 할 경우 쓸 것 같다.
사용 방법을 알아보면
코드를 설명하면 main routine에서 context를 생성해 sub routine 호출 시 파라미터로 넘겨주면 sub routine은 context.Done을 주시하고 있다. 그리고 1초에 한 번씩 트리거 되는 tick을 만들어 Tick이라는 문자열을 출력한다. 다시 main routine을 돌아와 10초 후 트리거되는 tick을 만들어 트리거 될 때 cancel 함수를 호출한다. 그로 인해 sub routine의 context.Done이 트리거 되면서 sub routine을 끝내고 main routine 또한 끝낸다. 하지만 당연하게 순서를 지켜주지 않기 때문에 channel이나 sync.WaitGroup을 추가해서 순서를 지키도록 작업할 수도 있을 것 같다.
26 단어 검색 프로그램 만들기
간단하게 로직을 설명하면 프로그램의 실행 파일을 실행할 때 arguments로 찾고 싶은 단어와 파일명(패턴)을 입력받아 파일을 찾은 후 파일을 한 줄 한 줄 읽으면서 찾고 싶은 단어가 포함된 줄이면 출력할 수 있도록 수집한 후 마지막에 수집한 파일명과 줄 수가 포함된 줄을 출력하는 프로그램이다.
본인이 코딩할 때는 파일 관련된 내용만 따라 치고 나머지는 코딩했다. 이제 코드를 보면
폴더 구조는 위와 같고 main 파일부터 보겠다.
os.Args로 입력한 인수를 받을 수 있고 args의 0번째 요소는 실행 파일명이고 1번째는 찾고자 하는 단어고 나머지는 파일명들이다. 다음으로 loader 파일을 보겠다.
처음에 main 함수의 os.Args를 출력해보지 않아서 입력한 패턴이 들어오는지 알았...다는... 우툰부 환경이라 그런가 filepath.Glob 함수가 어떤 의민지 모르겠지만 위 이미지는 간단하게 찾는 파일들이 있는지 없는지 찾고 없는 경우 에러를 반환하도록 만들었다. 에레가 발생하게 입력 후 출력을 보면
이렇게 출력된다. 에러가 발생하지 않았다 생각하고 마저 보면
fileNames를 순회하면서 fileScanner를 생성 후 init을 호출한다. init함수는 인수로 받은 fileName에 해당하는 파일을 열도록 시도한 후 에러가 발생하면 반환하도록 만들었다. 에러가 발생하지 않으면 goroutine을 생성해서 해당 파일에 단어가 있으면 findWordSender라는 channel을 이용해 해당 줄 정보를 푸시하면 findTextCollect 함수로 만든 goroutine에서 수집한다. context를 사용해 보기 위해 waitGroup의 Wait 함수가 끝난 후 cencle을 호출해 수집하는 goroutine도 끝내도록 코딩했다. 나머지는 출력 내용 만드는 거라 pass~
이번주도 끝~~~~~ ㅎㅎ
'Golang > Tucker' 카테고리의 다른 글
[묘공단] 6주차 (2) (0) | 2023.11.12 |
---|---|
[묘공단] 6주차 (1) (0) | 2023.11.05 |
[묘공단] 5주차 (2) (0) | 2023.10.29 |
[묘공단] 5주차 (1) (1) | 2023.10.29 |
[묘공단] 4주차 (2) | 2023.10.22 |