[performance] Go는 어떻게 그렇게 빨리 컴파일됩니까?

Go 웹 사이트를 둘러 보았지만 Go의 특별한 빌드 시간에 대한 설명을 찾지 못하는 것 같습니다. 언어 기능 (또는 그 부족), 고도로 최적화 된 컴파일러 또는 다른 제품입니까? 나는 Go를 홍보하려고하지 않습니다. 그냥 궁금 해서요



답변

의존성 분석.

이동 자주 묻는 질문은 다음과 같은 문장을 포함하는 데 사용 :

Go는 종속성 분석을 쉽게하고 C 스타일 포함 파일 및 라이브러리의 오버 헤드를 피할 수있는 소프트웨어 구성 모델을 제공합니다.

이 문구는 더 이상 FAQ에 없지만이 주제는 Google 토크 대화에서 자세히 설명합니다.이 주제는 C / C ++ 및 Go의 종속성 분석 접근 방식을 비교합니다.

이것이 빠른 컴파일의 주된 이유입니다. 그리고 이것은 의도적으로 설계된 것입니다.


답변

Go 컴파일러가 빠르다 는 것이 아니라 다른 컴파일러가 느리다고 생각 합니다.

C 및 C ++ 컴파일러는 엄청난 양의 헤더를 구문 분석해야합니다. 예를 들어 C ++ “hello world”를 컴파일하려면 18k 라인의 코드를 컴파일해야합니다.

$ cpp hello.cpp | wc
  18364   40513  433334

Java 및 C # 컴파일러는 VM에서 실행됩니다. 즉, 무엇이든 컴파일하기 전에 운영 체제가 전체 VM을로드해야하며 바이트 코드에서 네이티브 코드로 JIT 컴파일되어야합니다.

컴파일 속도는 몇 가지 요소에 따라 다릅니다.

일부 언어는 빠르게 컴파일되도록 설계되었습니다. 예를 들어, Pascal은 단일 패스 컴파일러를 사용하여 컴파일되도록 설계되었습니다.

컴파일러 자체도 최적화 할 수 있습니다. 예를 들어, Turbo Pascal 컴파일러는 수작업으로 최적화 된 어셈블러로 작성되었으며 언어 설계와 결합하여 286 클래스 하드웨어에서 작동하는 컴파일러가 매우 빠릅니다. 지금까지도 현대 파스칼 컴파일러 (예 : FreePascal)가 Go 컴파일러보다 빠르다고 생각합니다.


답변

Go 컴파일러가 대부분의 C / C ++ 컴파일러보다 훨씬 빠른 여러 가지 이유가 있습니다.

  • 가장 큰 이유 : 대부분의 C / C ++ 컴파일러는 컴파일 속도 관점에서 볼 때 예외적으로 나쁜 디자인을 나타냅니다. 또한 컴파일 속도 측면에서 C / C ++ 에코 시스템의 일부 (예 : 프로그래머가 코드를 작성하는 편집기)는 컴파일 속도를 염두에두고 설계되지 않았습니다.

  • 가장 큰 이유 : 빠른 컴파일 속도는 Go 컴파일러와 Go 언어에서 의식적인 선택이었습니다.

  • Go 컴파일러는 C / C ++ 컴파일러보다 간단한 옵티 마이저를 가지고 있습니다.

  • C ++와 달리 Go에는 템플릿과 인라인 함수가 없습니다. 즉, Go에서 템플릿 또는 함수 인스턴스화를 수행 할 필요가 없습니다.

  • Go 컴파일러는 하위 수준의 어셈블리 코드를 더 빨리 생성하고 옵티마이 저는 어셈블리 코드에서 작동하는 반면, 일반적인 C / C ++ 컴파일러에서는 최적화 패스가 원본 소스 코드의 내부 표현에서 작동합니다. C / C ++ 컴파일러의 추가 오버 헤드는 내부 표현을 생성해야한다는 사실에서 비롯됩니다.

  • Go 컴파일러는 사용 된 모든 어셈블리 코드를 거치고 C / C ++와 같은 다른 추가 작업을 수행하기 때문에 Go 프로그램의 최종 링크 (5l / 6l / 8l)는 C / C ++ 프로그램을 링크하는 것보다 느릴 수 있습니다. 링커는하지 않습니다

  • 일부 C / C ++ 컴파일러 (GCC)는 텍스트 형식 (어셈블러에 전달됨)으로 명령어를 생성하는 반면 Go 컴파일러는 이진 형태로 명령어를 생성합니다. 텍스트를 이진으로 변환하려면 추가 작업을 수행해야합니다.

  • Go 컴파일러는 소수의 CPU 아키텍처 만 대상으로하는 반면 GCC 컴파일러는 많은 수의 CPU를 대상으로합니다.

  • Jikes와 같은 빠른 컴파일 속도를 목표로 설계된 컴파일러는 빠릅니다. 2GHz CPU에서 Jikes는 초당 20000+ 라인의 Java 코드를 컴파일 할 수 있습니다 (그리고 증분 컴파일 모드는 훨씬 더 효율적입니다).


답변

컴파일 효율성은 주요 디자인 목표였습니다.

마지막으로, 빠른 속도를 목표로합니다. 단일 컴퓨터에서 큰 실행 파일을 빌드하는 데 최대 몇 초가 걸립니다. 이러한 언어 적 문제를 해결하기 위해 이러한 목표를 달성하기 위해서는 표현력이 있지만 가벼운 유형의 시스템; 동시성 및 가비지 콜렉션; 엄격한 의존성 사양; 등등.자주하는 질문

언어 FAQ는 구문 분석과 관련된 특정 언어 기능과 관련하여 매우 흥미 롭습니다.

둘째,이 언어는 분석하기 쉽게 설계되었으며 기호 테이블없이 구문 분석 할 수 있습니다.


답변

위의 대부분은 사실이지만 실제로 언급하지 않은 중요한 점은 종속성 관리입니다.

이동은 당신이 가져 오는 것을 패키지를 포함 할 필요가 직접 (그 이미 어떤 수입으로 그들이 필요). 이것은 모든 단일 파일 이 y 헤더 등을 포함하는 x 헤더를 포함하여 시작 하는 C / C ++와 완전히 대조적입니다 . 결론 : Go의 컴파일은 가져온 패키지 수에 따라 선형 시간이 걸리고 여기서 C / C ++는 지수 시간이 걸립니다.


답변

컴파일러의 변환 효율성에 대한 좋은 테스트는 자체 컴파일입니다. 주어진 컴파일러가 자체 컴파일하는 데 얼마나 걸립니까? C ++의 경우 시간이 오래 걸립니다 (시간?). 이에 비해 Pascal / Modula-2 / Oberon 컴파일러는 하나 미만으로 자체 컴파일됩니다 최신 머신에서 초 [1].

Go는 이러한 언어에서 영감을 얻었지만 이러한 효율성의 주요 원인은 다음과 같습니다.

  1. 효율적인 스캔 및 구문 분석을 위해 수학적으로 명확하게 정의 된 구문입니다.

  2. C / C ++에서와 같이 독립적 인 컴파일과 달리 헤더 파일을 불필요하게 다시 읽고 다른 모듈을 다시 컴파일하는 것을 피하기 위해 모듈 경계에 걸쳐 종속성 및 유형 검사 와 함께 별도의 컴파일 을 사용하는 형식 안전하고 정적으로 컴파일 된 언어 컴파일러는 이러한 교차 모듈 검사를 수행하지 않습니다 (따라서 간단한 한 줄 “hello world”프로그램의 경우에도 모든 헤더 파일을 반복해서 다시 읽어야합니다).

  3. 효율적인 컴파일러 구현 (예 : 단일 패스, 재귀 하향 하향식 파싱)-물론 위의 1 및 2 지점에서 크게 도움이됩니다.

이러한 원칙은 1970 년대와 1980 년대에 Mesa, Ada, Modula-2 / Oberon 및 기타 여러 언어로 이미 알려져 있으며 완전히 구현되었으며 현재는 (2010 년대) Go (Google)와 같은 현대 언어로의 길을 찾고 있습니다. , Swift (Apple), C # (Microsoft) 및 기타 여러 가지.

이것이 곧 예외가 아닌 표준이 되길 바랍니다. 거기에 가려면 두 가지 일이 발생해야합니다.

  1. 먼저, Google, Microsoft 및 Apple과 같은 소프트웨어 플랫폼 제공 업체는 애플리케이션 개발자가 새로운 코드 작성 방법을 사용 하도록 권장 하면서 기존 코드 기반을 재사용 할 수 있도록해야합니다. 이것이 바로 동일한 런타임 환경을 사용하기 때문에 Objective-C와 공존 할 수있는 Swift 프로그래밍 언어와 관련하여 Apple이 시도하는 것입니다.

  2. 둘째, 기본 소프트웨어 플랫폼 자체는 결국 이러한 원칙을 사용하여 시간이 지남에 따라 다시 작성되어야하며 동시에 모듈 식을 모 놀리 식으로 만들도록 모듈 계층 구조를 재 설계해야합니다. 이것은 물론 굉장한 작업이며 10 년 동안 더 잘 할 수 있습니다 (실제로 그렇게 할 수있을 정도로 용기가 있다면-Google의 경우 전혀 확실하지 않습니다).

어쨌든 언어 채택을 주도하는 플랫폼이며 다른 방식은 아닙니다.

참고 문헌 :

[1] http://www.inf.ethz.ch/personal/wirth/ProjectOberon/PO.System.pdf , 6 페이지 : “컴파일러가 약 3 초 안에 컴파일됩니다”. 이 인용문은 25MHz의 클럭 주파수에서 실행되고 1MByte의 메인 메모리를 갖춘 저가의 Xilinx Spartan-3 FPGA 개발 보드를위한 것입니다. 이것으로부터 1GHz 이상의 클럭 주파수와 몇 GBytes의 주 메모리 (즉, Xilinx Spartan-3 FPGA 보드보다 몇 배나 더 강력한)에서 실행되는 최신 프로세서의 경우 1 초 미만으로 쉽게 추정 할 수 있습니다 . I / O 속도를 고려할 때도 마찬가지입니다. Oberon이 2-4MB의 주 메모리를 가진 25MHz NS32X32 프로세서에서 실행 된 1990 년에 이미 컴파일러는 몇 초 만에 자체 컴파일되었습니다. 실제로 기다리는 개념컴파일러가 컴파일주기를 마치기 전까지는 Oberon 프로그래머에게는 완전히 알려지지 않았습니다. 일반적인 프로그램의 경우 컴파일러가 방금 트리거 한 컴파일을 완료하기를 기다리는 것보다 컴파일 명령을 트리거 한 마우스 버튼에서 손가락을 제거하는 데 항상 더 많은 시간이 걸렸습니다. 거의 제로에 가까운 대기 시간으로 즉각적인 만족감이었습니다. 그리고 당시에 사용 가능한 최고의 컴파일러와 완전히 동일하지는 않지만 제작 된 코드의 품질은 대부분의 작업에 상당히 좋았으며 일반적으로 상당히 수용 가능했습니다.


답변

Go는 빠르도록 설계되었으며 잘 보여줍니다.

  1. 종속성 관리 : 헤더 파일이 없으므로 직접 가져온 패키지 (가져 오는 것에 대해 걱정할 필요가 없음)를보아야하므로 선형 종속성이 있습니다.
  2. 문법 : 언어의 문법은 단순하여 쉽게 파싱됩니다. 기능의 수는 줄어들지 만 컴파일러 코드 자체는 빡빡합니다 (경로가 거의 없음).
  3. 과부하가 허용되지 않습니다. 심볼이 표시되고 어떤 방법을 참조하는지 알 수 있습니다.
  4. 각 패키지를 독립적으로 컴파일 할 수 있기 때문에 Go를 병렬로 컴파일하는 것은 간단합니다.

GO는 그러한 기능을 가진 유일한 언어는 아니지만 (모듈은 현대 언어의 표준 임), 잘 해냈습니다.