Go는 매우 빠릅니다. 성능은 Java나 C++와 거의 비슷합니다. 사용 사례에서 Go는 일반적으로 Python보다 40배 빠릅니다.
많은 애플리케이션에서 프로그래밍 언어는 애플리케이션과 데이터베이스 사이의 접착제 역할에 불과합니다. 일반적으로 언어 자체의 성능은 중요하지 않습니다. 하지만 Stream은 700개 기업과 5억 명 이상의 최종 사용자를 위한 시놉시스 및 채팅 플랫폼의 API 제공업체입니다. 수년 동안 Cassandra, PostgreSQL, Redis 등을 최적화해 왔습니다. 하지만 결국에는 사용 중인 언어의 한계에 도달하게 됩니다. Python은 훌륭한 언어이지만 직렬화/역직렬화, 정렬 및 집계와 같은 사용 사례의 경우 속도가 상당히 느립니다. 성능 문제가 자주 발생하는데, Cassandra는 데이터를 검색하는 데 1밀리초가 걸리고 Python은 그 다음 10밀리초 동안 데이터를 객체로 변환하는 데 소요됩니다.
Go 튜토리얼에서 제가 어떻게 작은 Go 코드를 시작했는지 살펴보세요. 훌륭한 튜토리얼이자 Go를 배우기 위한 훌륭한 출발점입니다.)
Go를 처음 사용하신다면 이 코드 스니펫을 읽고 놀라지 않으실 것입니다. 여기에는 몇 가지 작업, 데이터 구조, 포인터, 형식 및 내장된 HTTP 라이브러리가 나와 있습니다. 처음 프로그래밍을 시작했을 때 저는 항상 파이썬의 고급 함수를 사용하는 것을 선호했는데, 파이썬을 사용하면 코드를 작성할 때 매우 창의적으로 사용할 수 있습니다. 하지만 대부분의 프로그래머가 동의하겠지만, 이러한 기능은 다른 사람의 코드를 읽을 때 코드를 이해하기 어렵게 만드는 경우가 많습니다. Go는 기본에 충실해야 합니다. 따라서 다른 사람의 코드를 읽고 무슨 일이 일어나고 있는지 즉시 이해할 수 있습니다. 참고: 물론 실제로 얼마나 "쉬운"지는 사용 사례에 따라 다릅니다. 기본적인 CRUD API를 만들고 싶다면 Django+DRF 또는 Rails를 추천합니다.
언어로서 Go는 일을 단순하게 유지하려고 노력합니다. 새로운 개념을 많이 도입하지 않습니다. 매우 빠르고 사용하기 쉬운 단순한 언어를 만드는 데 중점을 둡니다. 고루틴과 채널이 유일한 혁신 분야입니다(100% 정석 CSP 개념은 1977년에 시작되었으므로 이 혁신은 오래된 아이디어에 대한 새로운 접근 방식에 가깝습니다). 고루틴은 Go의 경량 스레딩 방식이며, 채널은 고루틴 간의 통신을 위해 선호되는 방식입니다. 고루틴을 생성하는 데는 몇 킬로바이트의 추가 메모리만 필요하기 때문에 매우 저렴합니다. 고루틴은 매우 가볍기 때문에 수백 개 또는 수천 개의 고루틴을 동시에 실행할 수 있습니다. 채널을 사용해 고루틴 간에 통신할 수 있습니다. 고루틴과 채널 기반 동시성 접근 방식을 사용하면 복잡한 개발 없이도 사용 가능한 모든 CPU 코어를 사용하고 동시 IO를 매우 쉽게 처리할 수 있습니다. 고루틴에서 함수를 실행하려면 Python/Java에 비해 최소한의 샘플 코드가 필요합니다. 함수 호출 앞에 "go"라는 키워드만 있으면 됩니다.
동시성에 대한 Go의 접근 방식은 잘 작동합니다. 개발자가 비동기 코드 처리 방식에 세심한 주의를 기울여야 하는 Node와 비교하면 흥미로운 접근 방식이며, Go에서 동시성의 또 다른 중요한 측면은 경합 탐지기입니다. 이를 통해 비동기 코드에 경합 조건이 있는지 쉽게 확인할 수 있습니다.
현재 Go로 작성하는 가장 큰 마이크로서비스는 컴파일하는 데 4초가 걸립니다. 컴파일 시간이 느린 것으로 알려진 Java나 C++와 같은 언어와 비교하면 Go의 빠른 컴파일 시간은 생산성 측면에서 큰 장점입니다. 저는 프로그램을 컴파일하는 동안 낚시하는 것을 좋아하는데, 코드가 해야 할 일을 기억하면서 작업을 수행하는 것이 더 좋습니다.
먼저, 당연한 것부터 말씀드리자면 Go 개발자의 수는 C++나 Java와 같은 구형 언어에 비해 적습니다. StackOverflow에 따르면 개발자의 38%는 Java를, 19.3%는 C++를, 4.6%만이 Go를 알고 있습니다.GitHub 데이터도 비슷한 추세를 보여줍니다.Go는 Erlang, Scala, Elixir 같은 언어보다 널리 사용되지만 Java와 C++만큼 대중적이지는 않습니다. 다행히도 Go는 매우 간단하고 배우기 쉬운 언어입니다. 필요한 기본 기능만 제공하면 그뿐입니다. '지연' 선언과 내장된 동시성 관리, 그리고 '고루틴'과 채널이라는 새로운 개념이 도입되었습니다. 순수주의자들을 위해 설명하자면, 이러한 개념을 구현한 최초의 언어는 Go가 아니라 대중화시킨 최초의 언어입니다.) Python, Elixir, C++, Scala, Java 개발자는 누구나 팀에 합류하면 단순성 덕분에 한 달 안에 Go로 작업할 수 있습니다. 다른 언어보다 Go 개발자들로 팀을 구성하기가 더 쉽습니다. 이는 볼더나 암스테르담과 같이 경쟁이 치열한 생태계에서 인재를 모집하는 경우 큰 장점입니다.
우리 정도의 규모(약 20명)의 팀에게는 에코시스템이 매우 중요합니다. 모든 사소한 기능을 다시 개발해야 한다면 고객을 위한 가치를 창출할 수 없습니다. Go는 우리가 사용하는 도구에 대한 훌륭한 지원을 제공합니다. 엔티티 라이브러리는 Redis, RabbitMQ, PostgreSQL, 템플릿 구문 분석, 작업 스케줄링, 식 구문 분석, RocksDB에 사용되었습니다. Go의 에코시스템은 Rust나 Elixir 같은 다른 최신 언어에 비해 큰 장점이라고 할 수 있습니다. Java, Python, Node와 같은 언어만큼 좋지는 않지만 안정적이며 기본적인 요구 사항의 대부분은 이미 고품질 패키지를 사용할 수 있습니다.
Gofmt는 코드 서식을 지정하기 위해 Go 컴파일러에 내장된 훌륭한 명령줄 도구입니다. 기능적으로는 Python의 autopep8과 매우 유사합니다. 우리 대부분은 탭과 공백에 대해 논쟁하는 것을 좋아하지 않습니다. 서식 일관성은 중요하지만 실제 서식 표준은 그다지 중요하지 않습니다. gofmt는 공식적인 방식으로 코드의 서식을 지정하여 이러한 모든 논의를 피합니다.
Go는 프로토콜 버퍼와 gRPC를 최고 수준으로 지원합니다. 이 두 도구는 RPC를 통해 통신해야 하는 마이크로서비스를 구축하는 데 적합합니다. 사용자가 해야 할 일은 호출할 수 있는 RPC 호출과 그 호출에 필요한 매개변수를 정의하는 목록을 작성하는 것뿐입니다. 그러면 이 목록에 따라 서버 및 클라이언트 코드가 자동으로 생성됩니다. 생성된 코드는 빠르고 네트워크 공간을 거의 차지하지 않으며 사용하기 쉽습니다. 동일한 목록에서 C++, Java, Python, Ruby 등 다양한 언어에 대한 클라이언트 측 코드도 생성할 수 있으므로 내부 트래픽에 대한 모호한 REST 엔드포인트가 더 이상 필요하지 않으며 매번 거의 동일한 클라이언트 측 코드와 서버 측 코드를 작성할 필요가 없습니다.
Go에는 Ruby의 Rails, Python의 Django, PHP의 Laravel처럼 하나의 지배적인 프레임워크가 없습니다. 많은 사람들이 처음부터 프레임워크를 사용해서는 안 된다고 생각하기 때문에 이것은 Go 커뮤니티에서 뜨거운 주제입니다. 일부 사용 사례에서는 이것이 사실이라는 데 전적으로 동의합니다. 그러나 간단한 CRUD API를 구축하려는 사람이라면 Django/DJRF, Rails Laravel 또는 Phoenix를 사용하는 것이 더 쉽습니다. Stream 사용 사례의 경우 프레임워크를 사용하지 않는 것을 선호합니다. 그러나 지배적인 프레임워크가 없다는 것은 간단한 CRUD API를 제공하고자 하는 많은 신규 프로젝트에 심각한 단점이 될 것입니다.
Go는 단순히 함수에서 오류를 반환하고 호출 코드가 오류를 처리(또는 호출 스택으로 반환)하기를 기대하는 방식으로 오류를 처리합니다. 이 접근 방식은 효과적이지만 사용자에게 의미 있는 오류를 제공하는지 확인하기 위해 문제의 범위를 놓치기 쉽습니다. 오류 패키지는 오류에 컨텍스트와 스택 추적을 추가할 수 있도록 하여 이 문제를 해결합니다. 또 다른 문제는 오류를 처리하는 것을 잊어버리기 쉽다는 것입니다. errcheck 및 megacheck와 같은 정적 분석 도구를 사용하면 이러한 실수를 쉽게 방지할 수 있습니다. 이러한 해결 방법은 잘 작동하지만, 제대로 된 느낌은 아닙니다. 언어가 적절한 오류 처리를 지원해야 합니다.
Go의 패키지 관리는 기본적으로 완벽하지 않습니다. 특정 버전의 종속성을 지정하거나 재현 가능한 빌드를 생성할 수 없습니다.Python, Node, Ruby 모두 더 나은 패키지 관리 시스템을 갖추고 있습니다. 하지만 적절한 도구를 사용하면 Go의 패키지 관리도 잘 작동합니다. Dep를 사용하여 종속성을 관리할 수 있으며, 이를 통해 버전을 지정하고 수정할 수 있습니다. 또한, Go로 작성된 여러 프로젝트를 더 쉽게 작업할 수 있는 VirtualGo라는 오픈 소스 도구도 기여했습니다.
우리가 수행한 흥미로운 실험 중 하나는 Python에서 순위 피드 함수를 사용하고 이를 Go로 다시 작성하는 것이었습니다. 이 랭킹 방법의 예를 살펴보겠습니다.
이 랭킹 방법을 지원하기 위해 Python과 Go 코드 모두 다음을 수행해야 했습니다.
Python 버전의 랭킹 코드를 개발하는 데는 약 3일이 걸렸습니다. 여기에는 코드 작성, 단위 테스트, 문서 작성 등이 포함되었습니다. 그 다음에는 코드를 최적화하는 데 약 2주가 소요되었습니다. 최적화 작업 중 하나는 분수 표현식(simple_gauss(time)*popularity)을 추상 구문 트리로 변환하는 것이었습니다. 또한 미래의 특정 시간에 대한 점수를 미리 계산하기 위해 캐싱 로직을 구현했습니다. 이에 비해 이 코드의 Go 버전을 개발하는 데는 약 4일이 걸렸습니다. 성능은 더 이상의 최적화가 필요하지 않았습니다. 따라서 초기 개발은 Python이 더 빨랐지만, 궁극적으로 Go 기반 버전이 저희 팀의 작업을 훨씬 덜 필요로 했습니다. 또 다른 이점은 Go 코드가 고도로 최적화된 Python 코드보다 약 40배 더 빠르게 실행된다는 것입니다. 이것은 Go로 전환하면서 경험한 성능 향상의 한 가지 예일 뿐입니다.
우리 시스템의 다른 구성 요소 중 일부는 Python보다 Go에서 빌드하는 데 더 많은 시간이 걸립니다. 일반적인 추세는 Go 코드를 개발하는 데 더 많은 노력이 필요하다는 것입니다. 하지만 성능을 위해 코드를 최적화하는 데는 더 적은 시간이 소요됩니다.
우리가 평가한 또 다른 언어는 Erlang 가상 머신에 구축된 Xanadu.Elixir였습니다. 이 언어는 매우 매력적인 언어이며, 팀원 중 한 명이 Erlang에 대한 풍부한 경험을 가지고 있기 때문에 사용을 고려했습니다. 저희 사용 사례에서는 Go의 원시 성능이 훨씬 더 우수하다는 것을 알 수 있었습니다. Go와 Elixir 모두 수천 개의 동시 요청을 매우 잘 처리할 수 있습니다. 하지만 개별 요청의 성능을 살펴보면 우리 사용 사례에서는 Go가 훨씬 더 빠릅니다. 만병통치약을 선택한 또 다른 이유는 에코시스템이었습니다. 필요한 구성 요소의 경우 Go에는 더 성숙한 라이브러리가 있는 반면, Elixir 라이브러리는 프로덕션 환경에 적합하지 않은 경우가 많았습니다. 또한 Elixir를 사용할 개발자를 교육하거나 찾기도 더 어려웠습니다. 이러한 이유들로 인해 Elixir의 Phoenix 프레임워크는 매우 훌륭해 보였고 꼭 한번 살펴볼 가치가 있습니다.
Go는 동시성을 잘 지원하는 매우 고성능 언어입니다. C++나 Java와 같은 언어만큼이나 빠릅니다. 파이썬이나 루비보다 Go로 빌드하는 데 시간이 더 걸리긴 하지만, 코드를 최적화하는 데 많은 시간을 절약할 수 있습니다. Stream의 소규모 개발자 팀은 5억 명 이상의 최종 사용자와 소통하고 있습니다.Go는 강력한 생태계, 신규 개발자를 위한 쉬운 시작, 빠른 성능, 안정적인 동시성 지원, 효율적인 프로그래밍 환경이 결합되어 있어 훌륭한 선택입니다.Stream은 대시보드, 웹사이트, 머신러닝에서 개인화를 제공하기 위해 여전히 Python을 사용하고 있습니다. 시놉시스. 당분간은 파이썬과 작별을 고하지 않을 것이지만, 향후 성능 집약적인 코드는 모두 Go로 작성될 예정입니다. 새로운 채팅 API도 전적으로 Go로 작성되었습니다.