Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Go Language

Avatar for Jason Im Jason Im
September 26, 2014

Go Language

Open-source Language GO에 대한 소개

Avatar for Jason Im

Jason Im

September 26, 2014

Other Decks in Programming

Transcript

  1. 1

  2. 오늘 소개드릴 내용은 크게 3가지로 구분되는데, Go라는 언어에 생소하신 분들이

    많을 것 같아서 언어 자체를 소개하는데 많은 지면 을 할애했고, 끝에는 가볍게 Web Application 개발에 대해서 설명하겠습니다. 2
  3. 3

  4. 이 아이는 오늘 소개 드리는 Go라는 언어의 마스코트 땅다람쥐, 고퍼입니다.

    주제를 Go로 선정한 이유는 사내 개발 세미나에서 그 동안 다양한 주제를 다 뤘었지만 의외로 프로그래밍 랭귀지에 대해서는 언급한 적이 없었던 것 같아서 선정하 게 되었습니다. 요즘 개인적으로 토플을 공부하고 있는데, 외국어를 공부하면서 느끼는 점이 있습니다. 언어가 의사를 전달하는 도구이기 때문에 구사하는 언어가 제공하는 프레임 에 맞춰서 사고체계도 바뀐다는 점입니다. 프로그래밍도 마찬가지인 것 같습니다. 인터프리터 언어를 할 때와 컴파일 언 어를 사용할 때가 생각하는 방식이 많이 다르니까요 그런 점에서 Go는 많은 생각할 거리들을 제공하는 언어입니다. Go라는 새로운 도구를 익혀보는 시간이 되었으면 좋겠습니다. 4
  5. Go는 Google에 재직 중인 3명의 개발구루가 만든 언어입니다. C언어의 모태가

    되는 B언어를 만든 Ken Thompson, 켄 톰슨과 함께 UTF-8을 설계한 Rob Pike, V8 엔진 개발자였던 Robert Griesemer 슬라이드에 실린 켄 톰슨에 대한 인터뷰를 보면, “C++이 싫어서 언어를 설계해 봤는데 어떤 이유에서든지 불필요한 스펙이 발생하지 않도록 작성했다.” 라고 합니다. 구글에서 남는시간 프로젝트로 시작한 건데 이 엄청난 사람들은 1년의 시간 동안 파트타임으로 하면서 언어 스펙부터 컴 파일러까지 모두 완성을 시켰습니다. Google HQ에 재직 중이신 분이 Go가 그냥 흥미위주로 만들어진 언어가 아 니라 구글 내에 실제로 많은 Production project에서 Go를 사용한다는 이야기를 해주셔서 처음 이 언어에 관심을 가지게 되었습니다. 5
  6. Go는 인터프리트 언어의 프로그래밍이 쉽다는 점과, 정적 타입 언어가 가진

    효율성과, 컴파일 언어의 안정성을 하나로 묶으려고 시도한 프로젝트입니다. 이를 통해서 네트워크와 멀티코어 컴퓨팅을 쉽게 지원하고, 빌드하는 시간이 빠르길 원했습니다. 그래서 동시성과 가비지 콜렉션을 지원하고 의존성에 대한 스펙을 엄격하게 해야했습니다. 이런 것들은 라이브러리로 해결하기 힘들었기 때문에 언어를 만든 것입니다. Go는 탄생한지 5년 정도 되었고, 오픈소스임을 강조하고 있습니다. 구글의 사 유재산처럼 보이면 많은 개발자들이 참여하지 않을 것을 우려한 것 같습니다. 정적 타입을 가진 컴파일 언어지만 타입 추론을 하기 때문에 코드에서 선언 할 땐 타입을 생략하는 경우가 많이 있습니다. 클래스나 상속의 개념은 없습니다. 관련된 내용은 다시 설명드리겠습니다. 언어의 성능이야기 하는 것은 마치 “이 곳은 너무 평화롭군. Emacs는 최악이 다. Vi가 좋다고 생각한다” 라고 이야기하는 경우와 같지만, 기계어로 컴파일 되어 나오는 특성상 인터프리터 언어보다 빠를 수 밖에 없 습니다. 사실 Go는 굉장히 빌드가 빠르고 설계 단계에서도 그런 점을 많이 고려했다 고 하는데 의존성 관리와 체크도 상당히 간편하게 되어있어서 C언어로 코딩하면서 느낄 수 있는 좌절들을 상당히 줄여주고 코드도 짧게 해 주면서 고성능을 얻을 수 있다는 정도로 생각해주시면 될 것 같습니다. 6
  7. C에서 가장 많은 영향을 받았고 파스칼과 파이썬의 문법을 일부 차용했습니

    다. Java처럼 가비지 콜렉션을 지원합니다. 런타임 리플렉션을 통해서 컴파일 속 도를 높였습니다. UTF-8을 설계한 사람이 두명이나 있어서 영향을 받았는지 모든 입출력은 기 본적으로 유니코드입니다. 튜토리얼도 Hello World가 아니라 “Hello 세계” 라는 한자로 쓰여서 유니코드 사용을 강조하고 있습니다. Node.js의 NPM이나 bower, docker처럼 요즘 추세인 Remote Package Management를 지원합니다. 원하는 라이브러리나 공개된 타인의 패키지가 있으면 “go get ~” 을 입력하 면 바로 받아올 수 있습니다. 7
  8. Go의 중요한 미션 중 하나는 간편하게 동시성 코드를 작성하는 것입니다.

    쓰레드 생성의 부하를 줄이기 위해서 Goroutine이라는 경량 쓰레드를 지원하 는데, 그냥 새 쓰레드로 실행시키고 싶은 함수 앞에 “go”라는 디렉티브만 입력해주 면 그 함수는 새로운 쓰레드에서 돌게 됩니다. 사실 우리가 생각하는 OS의 쓰레드는 아닙니다. 사실 런타임의 Thread는 Worker Pool 형태로 관리됩니다. Go의 경량 쓰레드는 OS에서 제공하는 쓰레드가 아니라 coroutine처럼 독립 적으로 실행되는 함수들로 구성되어 있습니다. (coroutine은 caller-callee의 종속관계가 아니라 caller와 계속 대화를 주고받 는 방식으로 짜여진 함수입니다.) 실행중인 Goroutine이 Block되면 자동적으로 런타임 쓰레드에서 해당 Goroutine을 빼고 다른 Goroutine으로 교체합니다. 결국 개발자 인위적인 Thread나 Process의 생성은 없는 것입니다. Context-switching으로 인한 오버헤드가 굉장히 적고, 대신 Stack의 사이즈를 동적으로 관리합니다. Go는 Stack을 작게 만들기 위해서 분할 스택을 사용합니다. (분할 스택이란 heap 영역에 각각 독립된 stack처럼 동작하는 자료구조를 올 리는 것입니다. 구현은 List 같은 것이 될 수 있습니다. 기존의 stack이 동일한 주소공간을 공유하기 때문에 발생하는 문제들을 해결 합니다.) 그래서 신규 고루틴은 겨우 몇 kb만 할당받고, 공간이 부족하면 자동으로 공 8
  9. 간을 확장합니다. 오버헤드가 작아서 동일한 주소 공간 안에 수만개의 고루틴을

    생성할 수 있 습니다. 이런 특징 때문에 Goroutine을 호출해서는 Stackoverflow가 발생하지 않습니 다. Stack에 쌓는게 아니기 때문이죠. 힙이 꽉찼을 때 메모리 오류가 나는 것입니다. 채널은 동시성 모델중 CSP(Communicating Sequential Processes)이라는 것 에서 가져온 개념입니다. 채널은 값을 주고 받는 파이프인데, 송수신시 상대방이 준비 될 때까지 Block 되기 때문에 채널을 사용하는 고루틴 코드에 명시적인 락을 걸지 않고도 동기화 될 수 있 도록 합니다. Go는 객체지향 패러다임의 일부분만 차용하고 있고, 클래스와 상속같은 것은 지원하지 않습니다. 메소드 리시버라는 것을 함수 선언에 넣으면 그 함수는 리시버가 가르키는 타입에 부착된 함수가 됩니다. 타입은 구조체가 될 수도 있고, 재정의한 Premitive 타입이 될 수도 있습니다. Go에서 인터페이스는 메소드의 집합입니다. 어떤 인터페이스를 사용하겠다 고 따로 명시하는 것은 없고, 인터페이스 내의 함수를 구현하면 그냥 암시적으로 계약을 만족했다라고 추 론합니다. 8
  10. 위 파일을 hello.go 라고 저장한 뒤 go run hello.go 또는

    go build hello.go & hello 를 실행시키면 “Hello, 세계”가 출력된다. 9
  11. 10

  12. 함수를 호출 하는 예 선언을 왜 거꾸로 할까? 포인터 타입과

    변수명의 명확한 구분을 위해서 http://blog.golang.org/gos-declaration-syntax 패키지 밖으로 노출되길 원하는 함수는 첫 글자를 대문자로 해야 합니다. 11
  13. 변수를 선언하는 2가지 방식. 타입을 명시적으로 선언할 수도 있고, 컴파일러가

    리터럴을 보고 추론하도록 할 수도 있다. 이런 컴파일러의 Type Guessing 기능이 Go를 인터프리터언어처럼 느껴지도 록 만든다. 12
  14. 리턴을 여러 개 하는 예. 리턴값이 다수일 땐 input처럼 괄호를

    열어서 넣어주면 되고, 받을 때도 순서대로 받으면 된다. 13
  15. 이름이 있는 리턴값 리턴 값에 이름을 주는 경우 지역변수 중에

    같은 이름을 가지는 변수의 값을 return 문에서 보내게 됨. 타입이 같으면 타입은 한번만 써도 됩니다. 14
  16. 반복문의 3가지 경우. Go는 반복문이나 if문에 괄호를 넣지 않습니다. 2번째

    반복문은 특이하게 조건만 쓰여있는데, go는 while문이 없기 때문에 for에 저런 형태를 사용하면 됩니다. 3번째 반복문은 while(true) 무한반복이 됩니다. 15
  17. Go는 구조체를 제공합니다. 또, 포인터가 있지만 포인터 연산은 불가합니다. 값

    대신 레퍼런스를 전달하기 위한 용도로만 사용이 가능합니다. 포인터 연산을 두지 않은 이유는 개발자 과실로 잘못된 주소를 얻어 오는 것이 가능하기 때문도 있고, 가비지 콜렉터의 구현을 단순화하기 위한 목적도 있다고 합니다. 컴파일러 기술이 발전하여 포인터 연산을 이용하지 않더라도 Array 인덱스를 활용한 반복이 충분히 효율적이기 때문에 때문에 괜찮다고 설명하고 있습니 다. Go는 기본적으로 값에 의한 전달을 합니다. 17
  18. 배열의 초기화는 make로 할 수 있고 0에 상응하는 값이 들어갑니다.

    Foreach문은 GO에서는 for range인데 Key와 Value를 받을 수 있습니다. Key를 사용하지 않는다면 _ (underscore)로 처리하면 됩니다 19
  19. 반드시 구조체가 아니더라도 다른 패키지에 있는 타입이나 Primitive type이 아니면

    메소드를 붙힐 수 있습니다. 위의 예제는 float64라는 primitive를 재정의한 MyFloat에 메소드를 붙히고 있는데 가능합니다. 24
  20. 메소드에서 해당 타입의 실제값을 수정하고 싶다면 포인터로 명시해주어야 합니다. Go는

    기본적으로 값 전달을 하기 때문입니다. 맵, 배열의 슬라이스, 뒤에 나오는 채널만 기본적으로 참조를 전달을 합니다. 25
  21. 인터페이스는 메소드의 집합이고 사용을 위해 명시적으로 선언할 필요가 없 습니다.

    인터페이스에 기술된 메소드와 동일한 스펙을 만족하면 인터페이스를 암시적 으로 충족시켰다고 인지합니다. Float64를 반환하는 Abs() 함수가 있으면 되는데, MyFloat는 만족하고 Vertex의 포인터를 받는 Vertex의 Abs 함수도 만족하지 만 그냥 Vertex 값은 못받기 때문에 세번째는 오류가 납니다. 26
  22. Goroutine은 Go가 제공하는 경량 쓰레드입니다. Goroutine을 생성할 때마다 OS 단에서

    Thread를 만들진 않습니다. 공유자원으로의 접근은 반드시 동기화 되어야 합니다. 채널로 이런 문제를 쉽게 해결할 수 있습니다. 27
  23. 채널은 값을 주고받을 수 있는 타입이 존재하는 파이프입니다. 화살표 방향으로

    데이터가 흐르는데, 송수신시 상대방이 준비될 때까지 Block 되기 때문에 명시적으로 락을 걸필요가 없습니다 28
  24. 29

  25. ListenAndServe는 Host와 Port명을 받고 디폴트 동작을 할 함수를 받습니다. 디폴트가

    지정되어있다면 지정되지 않은 모든 요청은 디폴트 함수를 타게 됩 니다. Handle은 처리할 URL과 함수를 지정합니다. Handle되기 위해서는 ServeHTTP라는 이름의 위와같은 스펙을 만족하는 함 수가 타입에 부착되어 있어야 합니다. 그럼 인터페이스들의 정의는 패키지 문서에서 볼 수 있습니다. Go는 template이라는 패키지도 지원하는데 Go의 기본 템플릿 문법이 Mustache와 매우 닮아있어서 학습이 쉽습니다. 간단한 웹 어플리케이션 이라면 그냥 이런식으로 구현하면 되지만, 복잡한 REST가 들어간다면 Framework을 사용하기를 추천합니다. 30
  26. Martini와 Revel은 Go의 가장 인기있는 웹 프레임워크입니다. 그 밖에도 awesome-go를

    보시면 많은 유틸리티들을 보실 수 있습니다. 왠만한 것들은 다있습니다. 31
  27. 예를 들어 Martini는 이런 API를 제공합니다 위의 github.com 으로 시작하는

    import 문은 go get으로 다운 받을 수 있습 니다. 32
  28. Techempower라는 업체에서 2014년 5월에 실시한 벤치마크에 따르면 EC2 m1.large 인스턴스에서

    plaintext 전달 TPS가 netty는 약 20만, plain servlet은 6만, go는 4만 4천인 것을 볼 수 있습니다. Spring은 7800정도였습 니다. 33
  29. 실제로 일치하는지 확인하기위해서 AWS에서 nGrinder를 돌렸는데 Tomcat+Spring은 약 7300정도로 아까의

    벤치마크와 유사한 성능을 보여줬 습니다. Go는 13000 TPS 정도를 보였고 Tomcat+Spring 보다 2배 정도 성능이 좋았 습니다. netty의 성능이 상당히 좋다고 알려져 있어서 성능이 가장 중요한 API 서버를 개발한다면 netty를 사용하는게 좋을 수 있습니다. 처음에도 말씀드렸듯이 Go가 빠르긴 하지만 성능만 놓고 보면 아직 컴파일 러를 계속 개선중이라 다른 언어가 더 뛰어날 수 있습니다. Go의 장점은 문법이 자유롭고 짧은 코드로 많은 일을 할 수 있고 동시성처리 개발이 매우 간편하다는 점에 있습니다. 이런 점 때문에 크롤러나 배치성 작업을 위한 프로그램 개발에도 잘 Fit한다 고 볼 수 있습니다. Node.js는 멀티 프로세스나 멀티 쓰레드에 적합하지 않아서 Go나 Python으 로 그런 프로그램을 짜는게 좋을 수 있습니다. 34
  30. 35

  31. 예를 들어 Martini는 이런 API를 제공합니다 위의 github.com 으로 시작하는

    import 문은 go get으로 다운 받을 수 있습 니다. 36
  32. 37