Python,Java,C등은 고급언어를 사용합니다. 고급언어는 사람이 이해하기는 쉽지만 컴퓨터는 이해하지 못합니다.
컴퓨터는 오로지 0과1로 이루어진 Binary(machine code)만 이해할 수 있습니다. 그렇기 때문에 개발자가 고급언어로 작성한 소스코드를 machine code로 변환하는 작업을 Compile(컴파일)이라고 합니다. 이러한 작업을 하는 프로그램이 바로 Compiler와 Interpreter입니다.
Interpreter
- 프로그램 Runtime(실행시간)에 한 번에 한 문장씩 변환.
- 소스 코드를 분석하는데 걸리는 시간은 적지만 전체 실행 시간은 Compiler로 변환한 코드보다 상대적으로 더 느리다(한 문장씩 변환하고 실행하다 보니…).
- 중간 Object Code(목적 코드)가 만들어지지 않아 메모리 효율이 높다.
- 첫 오류를 만날 때까지 프로그램을 계속 번역하고 오류를 만나면 중지된다. 프로그램 실행 전에 오류를 발견하기 어렵다.
- Python, Ruby와 같은 언어들이 Interpreter를 사용.
- 파이썬의 경우 런타임중의 컴파일 과정에 렉서(lexer), 파서(parser) 를 거쳐서 바이트 코드를 만들어낸다. (렉서 : 요소를 하나하나 쪼갠다. / 파서 : abstract syntax tree, 구문분석)
- 어셈블리어는 cpu에 의존적이나, (예: 인텔 계열의 어셈블리어) 바이트코드는 그렇지 않다.
- 바이트코드는 가상머신(virtual machine) 위에서 돌아가기 때문에 어떤 cpu 위에서도 돌아갈 수 있다.
- 파이썬 초기 설치시 window용, mac용, linux용을 따로 받는 이유는 바이트코드에서 어떤 기계어로 바꿀지를 결정하기 위해서이다.
python 코드 --> 실행 & 런타임 시작 --> (컴파일) --> 바이트코드 --> VM --> 기계어
Compiler
- 프로그램 Runtime 전에 전체 소스 코드를 검사하여 machine code로 변환한다. Runtime되기 전에 변환은 시간이 오래걸리지만, 구동된 이후에는 하나의 패키지로 매우 빠르게 작동하게 된다.
- 소스 코드를 분석하는데 많은 시간이 들지만 전체 실행 시간은 Interpreter로 변환한 코드보다 비교적 빠르다.
- 링킹(linking)을 추가로 필요로 하는 중간 Object Code를 생성하여 더 많은 메모리를 필요로 한다.
- 전체 코드를 검사한 후에 오류 메시지를 생성한다. 그래서 실행 전에 오류를 발견할 수 있다.
- 런타임 이전에 이미 해석을 마치고 대게 컴파일 결과물이 바로 기계어로 전환되기 때문에 OS 및 빌드 환경에 종속적이다. 그러므로 OS환경에 맞게 호환되는 라이브러리와 빌드환경을 구분해서 구축해줘야 한다.
- C, C++, Java와 같은 언어들이 Compiler를 사용.
`C 코드` --(컴파일러)-->> `어셈블리어` --(어셈블러)-->> `기계어` --(링커)-->> `실행파일` -->> `런타임` 시작
Compiler 언어는 변환시 바로 machine code로 변환되어 CPU가 읽을 수 있습니다. 하지만 Interpreter 언어의 경우 변환시 바로 machine code로 변환되는 것이 아니라 Interpreter가 해석할 수 있는 Bytecode라는 machine code보다 추상적인 이진 표현법으로 먼저 변환 후 이 Bytecode를 Interpreter가 변환하여 machine code로 변환하게 됩니다.
그래서 Python과 같은 Interpreter 언어가 C나 C++와 같은 Compiler 언어 보다 상대적으로 느린 것입니다.
참고자료 : https://medium.com/@yeon22/term-compiler-vs-interpreter-2199abe0f01d
참고자료 : https://jins-dev.tistory.com/entry/Compiler-와-Interpreter-의-개념과-차이점
참고자료 : https://wayhome25.github.io/cs/2017/04/13/cs-14/