컴파일러는 빠른 컴파일 시간을 위해 멀티 스레딩을 사용합니까?


16

컴파일러 과정을 올바르게 기억하면 일반적인 컴파일러에는 다음과 같은 간단한 개요가 있습니다.

  • 어휘 분석기는 문자별로 소스 코드를 스캔하거나 스캔 기능을 호출 합니다.
  • 입력 문자의 문자열은 룩 셈스 사전과 비교하여 유효성을 검사합니다.
  • Lexeme이 유효한 경우 해당 Lexeme이 해당 토큰으로 분류됩니다.
  • 파서는 토큰 조합의 구문을 검증합니다. 토큰 별 .

이론적으로 소스 코드를 4 분의 1 (또는 분모)로 나누고 스캔 및 파싱 프로세스를 멀티 스레딩하는 것이 가능합니까? 멀티 스레딩을 사용하는 컴파일러가 있습니까?




1
@RobertHarvey 첫 번째 링크의 최상위 답변은 "하지만 컴파일러 자체는 여전히 단일 스레드입니다." 그래서 아니에요?
8protons

나는 당신이 나머지 답변, 특히 이것 과 내가 게시 한 두 번째 링크 를 읽는 것이 좋습니다 .
Robert Harvey

2
@RobertHarvey 여러분이 게시 한 내용을 이해하면서 게시 한 두 번째 링크는 컴파일 된 응용 프로그램의 멀티 스레드 버전을 생성하는 컴파일러에 관한 것입니다. 컴파일러 자체가 아닙니다. 공유 리소스에 감사하고 시간을내어 답변 해 주셔서 감사합니다.
8protons

답변:


29

대규모 소프트웨어 프로젝트는 일반적으로 비교적 독립적으로 컴파일 할 수있는 많은 컴파일 단위로 구성되므로 컴파일러를 여러 번 병렬로 호출하여 컴파일을 매우 세분화합니다. 이것은 OS 프로세스 수준에서 발생하며 컴파일러가 아닌 빌드 시스템에 의해 조정됩니다. 나는 이것이 당신이 요구 한 것이 아니라는 것을 알고 있지만 대부분의 컴파일러에서 병렬화에 가장 가깝습니다.

왜 그런 겁니까? 컴파일러가 수행하는 많은 작업이 병렬화에 쉽게 도움이되지는 않습니다.

  • 입력을 여러 청크로 나누고 독립적으로 lex 할 수는 없습니다. 단순성을 위해 lexme 경계에서 분할하고 싶기 때문에 (lexme 중간에서 스레드가 시작되지 않음) lexme 경계를 결정하려면 많은 컨텍스트가 필요합니다. 예를 들어, 파일 중간에서 점프 할 때 문자열 리터럴로 점프하지 않았는지 확인해야합니다. 그러나 이것을 확인하기 위해서는 기본적으로 이전에 등장했던 모든 캐릭터를 살펴 봐야합니다. 게다가, 렉싱은 현대 언어의 컴파일러에서 병목 현상이 거의 없습니다.
  • 구문 분석은 병렬화하기가 더 어렵습니다. 어휘를 위해 입력 텍스트를 분할하는 모든 문제는 구문 분석을 위해 토큰을 분할하는 데 훨씬 더 적용됩니다. 이 문제를 해결할 수있는 방법이있을 수도 있지만, 약간의 이점을 위해 불균형 적으로 복잡 할 것입니다. 파싱도 가장 큰 병목 현상이 아닙니다.
  • 구문 분석 한 후에는 일반적으로 이름 확인을 수행해야하지만 이로 인해 서로 밀접한 관계가 형성됩니다. 여기에서 메소드 호출을 해결하려면 먼저이 모듈에서 가져 오기를 해결해야하지만 다른 컴파일 단위 에서 이름을 해석해야 합니다. 언어에 해당하는 경우 유형 유추와 동일합니다.

이 후 약간 쉬워집니다. 원칙적으로 형식 검사 및 최적화 및 코드 생성이 기능 단위로 병렬화 될 수 있습니다. 컴파일러 가이 작업을 수행하는 경우 거의 알지 못합니다.이 작업을 동시에 수행하는 것이 매우 어려울 수 있습니다. 또한 대부분의 대규모 소프트웨어 프로젝트에는 너무 많은 컴파일 단위가 포함되어있어 "여러 컴파일러를 병렬로 실행"접근 방식으로 모든 코어 (및 경우에 따라 전체 서버 팜)를 유지하기에 충분합니다. 또한 대규모 컴파일 작업에서 디스크 I / O는 실제 컴파일 작업만큼 병목 현상이 발생할 수 있습니다.

코드 생성 및 최적화 작업을 병렬화하는 컴파일러를 알고 있습니다. Rust 컴파일러는 백엔드 작업 (실제로는 "중간 엔드"로 간주되는 코드 최적화를 포함하는 LLVM)을 여러 스레드로 분할 할 수 있습니다. 이것을 "코드 생성 단위"라고합니다. 위에서 설명한 다른 병렬화 가능성과 달리, 다음과 같은 이유로 경제적입니다.

  1. 이 언어에는 컴파일 단위가 크므로 (C 또는 Java와 비교) 코어가있는 것보다 적은 컴파일 단위가있을 수 있습니다.
  2. 병렬화되는 부분은 대개 컴파일 시간의 대부분을 차지합니다.
  3. 백엔드 작업은 대부분 당혹스럽게 병렬입니다. 각 기능을 독립적으로 기계 코드로 최적화하고 번역하기 만하면됩니다. 물론 절차 간 최적화가 있으며 코드 단위는이를 방해하여 성능에 영향을 주지만 의미 상 문제는 없습니다.

2

컴파일은 "엄청나게 평행 한"문제입니다.

아무도 하나의 파일을 컴파일하는 시간에 신경 쓰지 않습니다. 사람들은 1000 개의 파일을 컴파일 할 때 걱정합니다. 또한 1000 개의 파일에 대해 프로세서의 각 코어는 한 번에 하나의 파일을 행복하게 컴파일하여 모든 코어를 완전히 바쁘게 유지할 수 있습니다.

팁 : "make"는 올바른 명령 행 옵션을 제공하면 여러 코어를 사용합니다. 그렇지 않으면 16 코어 시스템에서 한 파일을 차례로 컴파일합니다. 즉, 빌드 옵션을 한 줄 변경하여 16 배 더 빠르게 컴파일 할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.