|
Go는 2009년 Google에서 설계한 프로그래밍 언어입니다. Go를 한 문장으로 표현하면 간결함(Simplicity)과 견고함(Robustness)의 균형을 맞춘 언어입니다. Go는 Docker 및 Kubernetes와 같은 클라우드 관련 유명 라이브러리 개발 언어로 잘 알려져 있지만 Go를 통해 범용(general-purpose) 프로그래밍 언어로서 백엔드(Backend)뿐만 아니라 블로그(Hugo), 게임 개발(Ebitengine)과 같은 프론트엔드 개발까지 할 수 있습니다. 이 글에서는 Go의 세 가지 특징과 주로 사용하는 문법을 서술하고자 합니다. |
Go의 세 가지 특징
Go는 다음과 같은 세 가지 특징을 가집니다. 하나씩 살펴보겠습니다.
1. 간결한 문법(Minimal syntax)
Go는 코드가 직관적으로 보일 수 있도록 최소한의 문법만을 구현하였습니다. 예를 들어 프로그래밍의 핵심 중 하나인 반복문의 경우 for 키워드 하나로 모두 수행합니다. 반대로 Python은 for외에도 while, list comprehension, map, filter 등 수많은 방법이 존재합니다. 이렇다보니 Go에서 특정 동작을 수행하는 코드는 작성자에 관계 없이 거의 동일한 형태로 작성됩니다. 이리하여 표준 라이브러리 를 비롯한 다른 사람의 코드를 마치 나 자신이 작성한 코드처럼 읽을 수 있습니다. 개인적으로 제가 Go에서 제일 마음에 들어하는 특징입니다.
2. 정적 타입(Statically typed language)
프로그램은 코드(code)를 통해 작성됩니다. 코드는 컴파일(compile) 과정을 통해 컴퓨터가 실행 가능한 파일로 바뀝니다. 정적 타입 언어는 프로그램이 실행 되기 이전인 컴파일 과정에서 변수의 타입이 결정되는 언어를 말합니다. 정적 타입 언어에서는 코드 작성 시 각 변수는 정해진 타입의 값만 담을 수 있게 제한됩니다. 대표적인 정적 타입 언어는 C와 C++가 있습니다. 반대로 동적 타입 (Dynamically typed) 언어는 변수의 타입이 실행 후에 결정되는 언어입니다. 대표적인 동적 타입 언어는 Python과 Javascript가 있습니다. 정적 타입 언어가 동적 타입 언어보다 엄격하여 코드 작성에 있어 불편할 수 있습니다. 하지만 오류를 초기에 탐지할 수 있고 외부 라이브러리 사용이 용이해진다는 장점이 있습니다.
3. 강력한 동시성 지원(Built-in concurrency)
동시성(Concurrency)이란 여러 개의 작업을 동시에, 혹은 그에 준하게 처리하는 능력을 말합니다. 동시성을 고려하여 프로그램을 작성하면 CPU를 비롯한 컴퓨팅 자원을 효과적으로 사용할 수 있습니다. Go에서는 goroutine과 channel을 통해 동시성 프로그래밍 기능을 쉽게 활용할 수 있습니다. 자세한 것은 다음 장에서 살펴 보겠습니다.
동시성 프로그래밍 - Goroutine
goroutine[고루틴]은 Go 프로그램 내에서 관리되는 내부 thread[스레드]입니다. 하나의 process[프로세스]는 여러 개의 thread를 가질 수 있고, 하나의 thread는 여러 개의 goroutine을 가질 수 있습니다. 운영 체제(OS) 차원에서 관리되는 thread보다 빠르고 효율적인 메모리 사용이 가능합니다. go를 통해서 goroutine을 하나 시작할 수 있습니다. 실행하는 즉시 main 함수를 통해 생성된 goroutine과 별개의 goroutine이 되므로 새로 생성된 goroutine이 작업을 모두 마칠 때까지 main에서 기다리는 과정이 필요합니다. 제일 간편한 방법은 time.Sleep으로 정해진 시간만큼 기다리는 것입니다.
동시성 프로그래밍 - Channel
두 개의 goroutine은 하나의 channel[채널]을 공유하여 통신할 수 있습니다. 값을 주고 받을 수 있고, 한 쪽이 준비가 될 때까지 다른 한 쪽을 기다리게(blocking) 할 수 있습니다. Channel은 1급 객체(first-class object)이므로 마치 숫자 값처럼 새 goroutine을 시작할 때 함수의 파라미터로 전달하여 사용할 수 있습니다.
Channel 반복문
하나의 channel을 통해 여러 개의 값을 보내는 경우가 있습니다. 이 경우 for-range구문을 통해 channel에 값이 들어올 때마다 그 값을 꺼낼 수 있습니다. range문은 채널이 닫히지 않는 한 계속 값을 받으려고 시도합니다. 따라서 range문을 사용한다면 channel에 필요한 값을 전부 전달한 뒤 더 이상 값이 들어오지 않는다는 사실을 close문을 통해 명시적으로 밝혀야 합니다.
동시성 프로그래밍 - select: 다수의 goroutine 기다리기
select구문을 통해 여러 개의 goroutine를 한 번에 기다릴 수 있습니다. select문은 switch문과 비슷하게 생겼습니다. switch문 예시는 아래 링크를 확인해주세요.
- https://github.com/hndada/go-tutorial/blob/main/04_if/main.go
goroutine들은 channel을 통해 통신을 합니다. case문으로 기다리고자 하는 goroutine의 channel을 원하는 만큼 명시하여 여러 개의 goroutine을 기다릴 수 있습니다. 등록된 channel들 중 어느 하나라도 값을 전달해주면 select문 전체가 종료됩니다.
예제 5에서는 goroutine이 보내온 결과물을 지속적으로 처리하도록 for loop을 추가하였습니다. 프로그램이 특정 시간이 지나면 종료될 수 있게 timeout을 넣을 수 있습니다. 예제에서는 3초 이상 어떠한 결과물이 나오지 않으면 프로그램을 종료시킵니다.
동시성 프로그래밍 예제
제 집에는 삼성 공기청정기와 전자레인지가 있습니다. 두 제품은 사물인터넷(Internet of things; IoT)으로 연결되어 있어서 제 휴대폰에 설치된 SmartThings를 통해 상태를 확인하고 행동을 제어할 수 있습니다. 예제 6에서는 SmartThings와 같은 프로그램을 간단하게 재현해보고자 합니다. 동시성 프로그래밍을 활용하여 2초 뒤에 전자레인지가 작동하게 하고 전자레인지의 가동이 완료되면 곧바로 공기청정기가 작동하도록 하고자 합니다.
위 예제에서 main 함수의 for문에 다다랐을 때에는 전자레인지와 공기청정기, SmartThings (main goroutine) 총 3개의 goroutine이 작동하고 있습니다. 전자레인지가 가동되고 곧 종료되면 전자레인지와 공기청정기가 공유하는 channel에 메시지가 전송됩니다. 공기청정기는 이 메시지를 통해 활성화되어 작동합니다. 작업이 완료되면 다시 channel에 작업 완료 메시지를 전송합니다. 현재 select문에는 10초 후 프로그램을 종료시키는 코드만 있습니다. 여기에 case문을 추가하여 다양한 정보를 주고 받을 수 있습니다.
마무리
Go는 goroutine과 channel을 통해 언어 차원에서 동시성을 지원합니다. select와 for 반복문을 결합하여 여러 goroutine이 보내온 결과물을 한 번에 지속적으로 처리할 수 있습니다. goroutine은 간결성과 기능성을 모두 갖추고자 하는 Go 설계 철학을 느낄 수 있는 개념 중 하나입니다. 이번 기회에 Go를 활용한 개발을 경험해보는 것을 추천 드립니다.
감사합니다.
|
|
