본문 바로가기

Learning

프로그램언어 GO 흘끗 보기

주중에 프로그램 언어인 GO에 대한 소개 메일을 받아보고 갑자기 언어에 대해 궁금해졌다. 관련 책을 간단히 읽고 정리해봤다. 깊은 내용은 없다.


GO에 대한 간단한 소개

2007년도쯤 구글에서 고안된 프로그램 언어로 인터넷상에서 혼동되지 않기 위해 'GOLANG'으로 호칭한다. 이 문서에서도 GOLANG으로 호칭한다. GOLANG관련 책 혹은 문서들을 보면 아래의 항목으로 요약해서 언어를 설명한다.

  • statistically-typed language의 빠른 성능, 안정성
  • dynamically-typed interpreted language의 편리함
  • 아주 쉬운 병렬/분산 프로그래밍
특성을 보면 세상의 모든 언어의 장점만을 모은 것 같지만, 세상에 그런 물건은 없다. GOLANG의 장점을 얘기할 때, 빠른 컴파일 속도와 빠른 실행 속도를 든다. 그러나 빌드된 파일의 크기는 생각외로 상당히 크다. 간단한 예로 "Hello world"를 찍는 예제 코드를 빌드한 결과 파일의 크기는 2Mbyte에 이른다. JAVA의 경우는 470여 바이트였다. 무려 수천배의 차이가 난다. (GO ver 1.9.1, JAVA ver 1.8)

아무튼 어떤 언어든 실전에 써보기 전까지는 장단점을 파악하기는 쉽지 않다.

SYNTAX

느낌은 자바, C, 파이썬, 파스칼등을 짬뽕해 놓은 느낌이다. 그러나 현대의 몇몇 언어의 난해한 문법은 아니고 전통적인 프로그램 코드 양식을 크게 벗어나지 않는다. 그래서 문법에 익숙해지기 쉬었다. 

개인적으로 좋아했던 파스칼의 작은 자취를 느낄 수 있어서 공부 하면서 기분이 좋아지기도 했다. 파스칼에서 쓰던  할당연산자가 "Short variable declaration" 연산자로 사용되었다.
var name = "Go"      // 기본 변수 선언문
name := "Go"           // 축약된 변수 선언문 'var'를 생략하고 연산자로 ':='를 사용

조금 재밌었던 것은 키워드를 구문상 배치하는 순서가 약간 코믹했다. 

var marry []string         // 전통적인 언어에선 주로 'string[]', '[]'부분을 앞에 놓았다.


func myfunc bool {        // 전통적인 언어에선 "function bool myfunc " 식인데, 반환 데이터형을 

...                                   // 뒤에 배치했다.

}


func sum(a int, b int) {    // "int a, int b"와 비교해보면 피식하게 된다.

...

}


defer

C/C++, JAVA등을 사용하던 사람들에게 생소한 키워드중의 하나는 'defer'이다. 일종의 finally문과 비슷하게 동작하는데, 우리가 좀더 자유롭게 코딩할 수 있게 해준다.

// GO defer 사용 예

func testdefer(fname string) {

    defer fmt.Printf("End!!!")

    ...

    file := os.Open(fname)

    ...

    defer file.Close()


    // Another codes

    ....

}


// JAVA finally 구문 예

public void testdefer(String fname) {

     InputStream input = null;

     try {

           input = new FileInputStream(new File(fname));

           ...

           // Another codes

     }

     catch(Exception e) {

           ...

     }

     finally {

           System.out.println("End!!!");

           try { input.close(); } catch(Exception e) { }

    }

}


'defer'키워드의 동작은 파란색 글상자 안의 JAVA코드의 finally문과 비교해보면 어떻게 동작하는지 이해하기 쉽다. 


panic - recover

또다른 생소한 키워드는 'panic'과 'recover'이다. 'panic'키워드는 JAVA의 'throw'와 유사하다. 그러나 'recover'키워드는  'catch'에 대응하는 것 같지 않다.

// GO panic - recover 사용 예

func save(name string) {

     ...

     panic("Exception !!!")

     ...


func main() {

     ...

     defer func() {

          if ( r := recover(); r != nil {       // recover함수를 호출한다.

               fmt.Println("ERROR=", r)

          }

     }

     ...

}


private void save(String name) throws Exception {

     ...

     throw new Exception("Exception !!!");

     ...

}


public static void main(String[] args) {

     ...

     try { ... }

     catch(Exception e) {

          System.out.println("ERROR=" + e.getMessage());

     }

     ...

}


try-catch구문과 같은듯 다른듯 하다. GOLANG에서 <exception>에 해당하는 <panic>은 recover()함수를 호출해야 확인할 수 있다. 이것은 아마도, 대개 try-catch구문은 프로그램의 성능에 부담을 주는데, 적당한 타협지점을 찾은 듯 하다. JAVA는 throws문이 있는 함수를 호출할 때, try-catch문을 반드시 써야 되는데, GOLANG은 이 것을 해도 되고 안해도 된다. 


Concurrency

쓰레드 제어, 동기화등에 대한 GOLANG의 문법은 스스로 자랑스러워 할 만했다. 정말로 간단하고 명료했다. 어쩌면 매뉴얼이 필요없을 정도로 직관적으로 잘 설계되었다. 같은 작업을 하는 코드를 GOLANG과 JAVA로 짜봤다. 이 둘을 비교하는 것만으로도 GOLANG의 Concurrency에 대한 문법은 충분히 이해된다. 


코드의 로직은 아래와 같다.

  • 메인쓰레드(Tm)외 2개의 쓰레드가 동작한다. 하나는 Coworker(T1) 다른 하나는 Guest(T2)라 한다.
  • Tm과 T1은 서로 데이터를 주고 받으면 동기화 된다.
  • T2는 다른 것들 상관없이 비동기로 동작한다.
  • Tm과 T1이 서로 10번 데이터를 주고 받으면 프로그램을 종료한다.
    • GOLANG은 제공하는 채널을 이용했고
    • JAVA는 Exchanger를 이용했다.
...
func main() {
    ...
    go guest()                            // 쓰레드상에서 비동기로 guest함수 실행
    go coworker(chOut, chIn)   // 쓰레드상에서 비동기로 coworker함수 실행
   ...
}

func coworker(fromMain <-chan int, toMain chan<- int) {
    ...
}.

private void mainRun()

{

    ...

    threadPool.execute(this.guest);            // 쓰레드상에서 비동기로 Guest 실행

    Runnable coworker = new Coworker(chOut, chIn);

    threadPool.execute(coworker);            // 쓰레드상에서 비동기로 Coworker 실행

   ...

}


private class Coworker implements Runnable

{

    public Coworker(Exchanger<Integer> fromMain, Exchanger<Integer> toMain)
    ...
}


전체 내용은 따로 첨부파일로 올렸다. 관심있는 분들은 비교해보세요. 간단한 로직인데..

sample-codes.zip

 

 소스파일 크기

빌드파일 크기 

 GOLAN

 44줄

 약 1900K

 JAVA

 94줄

 약 4K


성능은 어떻게 측정해야할지 몰라 생략했다. 그리고 개인적으로 주요 언어의 성능 비교는 점점더 무의미해진다고 본다. 분산 및 병렬처리 기술의 발전에 따른 것도 있고, 기계학습등의 통계패키지 등을 보면, 어떤 언어를 사용하더라도 결국 BLAS같은 포트란등으로 짜여진 라이브러리를 이용하기 때문이다.


결론

GOLANG은 C/C++, JAVA등을 사용해본 사람들에게 무척 친숙한 문법을 제공한다. Spark같이 개인적으로 괴상한 문법은 거의 없다. 따라서 C로부터 파생된 언어들의 문법에 익숙한 사람은 금방 사용할 수 있다고 보이며, 특히 쓰레드, IO등의 제어 코드가 정말로 명료하게 간단하다. 심지어 포인터 기능도 갖고 있는데, JAVA의 대안보다는 C/C++의 대안으로 좋을 듯 하다. 분명 좋은 언어임에 틀림없다.


여담으로 C/C++로 짜여진 크롬 브라우저를 보통의 PC급에서 빌드할 경우 대여섯 시간 이상 걸리는데, 이런 규모의 코드도 GOLANG에서는 수분에서 십여분내에 컴파일을 할 수 있다면, 과연 기존의 코드들을 GOLANG으로 모두 옮기는 작업을 할 수 있을까? 


sample-codes.zip


'Learning' 카테고리의 다른 글

JAVA9 jshell(REPL)  (0) 2018.01.29
My-SQL 8 RC2 흘끗보기 - JSON  (0) 2017.11.11
자바스크립트 프레임웤 vue.js 흘끗보기  (0) 2017.09.30
JAVA 9 모듈방식(modularity) 코딩 힐끗보기  (0) 2017.09.08
JAVA 람다함수 총정리  (0) 2017.08.01