Python&Java&C의 성능비교

 

Q. 왜 Python은 C언어보다 느린가?

1. Python의 변수는 Dynamically Typed이기 때문이다
Static Typing :vs: Dynamic Typing
  • Static typing은 runtime 이전(또는 compile-time)에 하는 type checking

    :large_blue_circle: 장점 : 실행 속도가 빠름, 컴파일 최적화를 통해 runtime 효율성 향상 및 메모리 사용 절약 가능

    :red_circle: 단점 : development-time이 길어 빠르게 변화하는 요구사항에 대처하기 어려움

  • Dynamic typing은 runtime에 하는 type checking

    :large_blue_circle: 장점 : development-time이 짧고 빠르게 변화하는 요구사항에 대처하기 쉬움

    :red_circle: 단점 : type checking을 runtime에 하기 때문에 실행 속도가 느림, runtime error가 비교적 많이 발생

Example
  • Dynamic Typing은 runtime에 type checking을 함으로써 모든 작업에 더 많은 단계가 포함되어 있다는 것을 의미한다. Statically typed language인 C 언어의 변수와 Dynamically typed language인 Python 언어의 변수를 활용한 덧셈과정을 살펴보면 단계 수가 차이나는 걸 바로 확인할 수 있다.

    Screen Shot 2021-08-25 at 3.26.51 PM

2. Python은 Interpreted되기 때문이다
Interpret :vs: Compile
  • 프로그램 언어를 해석하고 실행시키는 대표적인 방법으로 Compile 과 Interpret 방식이 있다

  • Complie

    • 과정

    Screen Shot 2021-08-25 at 9.33.53 PM

    1. Preprocessing (预处理)

      • '#’ 으로 시작하는 부분에 대해서는 C컴파일러가 쉽게 인식할 수 있도록 C언어 소스를 재정리
      • 주석 제거
      • source code file을 Preprocessing 한 다음 확장자가 .i 또는 .c 인 file을 생성하게 됨
    2. Compile (编译)

      • 전처리가 끝난 source code를 기반으로 assembler code file (확장자가 .s인 file) 를 생성
    3. Assemble (汇编)

      • assembler code를 바탕으로 Object file (확장자가 .o인 file) 을 생성
      • Object file 부터는 Binary code로 되어있어 사람 이해할 수 없는 형태
    4. Link (连接)

      • Link 작업을 통하여 여러 Object file 파일들과 표준 C Library(확장자가 .a 또는 .so인 file), 사용자 Library들을 합쳐서 실행 파일을 만들 수 있다

      • Static Link :

        :small_blue_diamond: Linker가 프로그램이 필요로 하는 부분을 Library에서 찾아 실행파일에다가 바로 복사

        :small_blue_diamond: 직접 구현한 code를 library화 시켜 기술 유출 방지로 사용 가능

        :small_blue_diamond: 실행 파일 내에 library code가 저장되기 때문에 메모리를 많이 잡아먹음

      • Dynamic Link :

        :small_blue_diamond: 어떤 기능이 실행 파일에 직접 덧붙여 지지 않고, library file에 독립적으로 존재하다가 프로그램이 실행될때 동적으로 링크되어 사용됨

        :small_blue_diamond: 최근 소프트웨어들은 Static Link를 하용하면 실행파일이 너무 커져서 Dynamic Link 사용

        :small_blue_diamond: 내 프로그램 영역에서 Library가 저장되어 있는 주소로 jump하는 거라 성능상 overhead가 듬

        :small_blue_diamond: Library만 version up이 되면 그거에 대한 성능을 내가 그대로 받을 수 있다

      • 성능 상으로는 Static Link이 좋지만 메모리 관리 차원에서는 Dynamic Link가 좋음

    • 파일의 변천사

      Screen Shot 2021-08-25 at 10.54.49 PM

    • 최적화

      • 같은 기능의 프로그램을 만들지만, 실행 속도나 메모리 점유율이 낮아지도록 최적의 코드로 만드는 것을 의미한다. 코드의 최적화는 크게 두가지로 나뉜다 :

        1. 중간코드의 최적화 : Source Code를 기반으로 공통 부분과 불필요한 부분을 제거한다.

        2. 목적코드의 최적화 : 메모리 로드의 기준에서 가장 효율적인 메모리나 레지스터의 할당을 하도록 한다.

  • Interpret

    • 고급언어로 작성된 프로그램을 한문장씩 읽고 번역 후 실행하는 방식
    • 프로그래머가 수정한 사항이 바로 반영
    • source code의 일부를 입력으로 넣기 때문에 컴파일타임 에러를 못잡아냄
    • Interpreter가 설치된 곳 이면 어느 곳에서도 실행이 가능하므로 프로그램 이식성이 높음
  • 컴파일러는 반복되거나 불필요한 연산을 미리 내다보고 최적화된 실행 파일을 생성하여 실행 속도를 높일 수 있다
  • 하지만 Python interpreter는 컴파일되지 않은 source code를 interpret하고 실행시키기 때문에 실행시간이 더 걸린다
3. Python의 Object model은 비효율적인 Memory access가 발생할 수 있기 때문이다
  • 특히 순차적인 데이터 구조에서 연속적인 데이터에 대해 동작을 할 경우 비효율적인 Memory access가 발생할 수 있다

    array_vs_list

    :warning: 参考 : Numpy 배열은 C의 Array과 유사함

    • Array는 반드시 할당된 메모리 공간은 연속적이라는 것이다, 그리고 Array의 모든 아이템들이 똑같은 사이즈를 가진다

    • 반면, List는 index를 갖지만 이는 몇 번째 데이터인가 정도를 의미한다, List는 아이템들의 메모리 주소가 연속적일 수도 있고, 아닐 수도 있다.

정리

Python이 C보다 느린 이유들 :

  1. Python의 변수는 Dynamically Typed이기 때문에 Runtime 때 C의 변수보다 더 많은 과정이 필요하다.
  2. Python은 Interpreter 언어이다. Interpreter 언어는 Compiled 언어와는 달리 코드를 한 줄씩 번역하고 실행하는 방식이기 때문에 실행 속도는 Compiled 언어인 C 보다 느리다.
  3. Python에서 List 같은 순차적인 데이터 구조는 C의 순차적인 데이터 구조보다 Memory access가 비효율적이다

Q. 그럼 Python과 Java 중 어떤 것이 빠른가?

Screen Shot 2021-08-26 at 3.45.10 PM

  • 실행 시간으로 봤을 땐 Java가 보통 더 빠르다. Interpreter 입장에선 사람이 알아보는 source code를 machine code로 바꿔서 처리하는 거 (Python) 보단 컴파일러를 거쳐나온 bytecode를 바로 처리하는게 (Java) 더 빠를 수 밖에 없다.

  • Example. 0 ~ 99 숫자를 “-” 로 이어라 (0-1-2-3-4 … -97-98-99)

    Screen Shot 2021-08-26 at 4.00.28 PM

    Python : 0.323 초

    Java : 0.198 초

  • 프로그램 실행 시간으로 봤을 때 무조건 빠른 프로그래밍 언어를 선택해야되는건 아니다

    • Java Interpreter(JVM)은 컴파일러를 거쳐나온 bytecode를 바로 처리할 수 있기 때문에 빠르다
    • 즉, Java는 실행시간이 Python 보다 빠르지만 bytecode가 build-up되지 않으면 무용지물이다
    • 프로젝트의 Source code가 커지면 Compile 시간도 고려를 해야된다

Q. 그렇다면 왜 Python을 사용하나?

  • 이렇게 본질부터 비효율적임에도 불구하고, 왜 우리는 파이썬을 사용하려고 생각할까?
    • Dynamic typing은 Python을 C보다 사용하기 쉽게 해줌
    • 이 유연함은 개발시간의 효율적인 사용을 이끌어냄
    • Python은 GLUE 언어라고도 부르는데, 그 이유는 다른 언어들과 잘 어울려 다른 언어와 결합해서 사용할 수 있기 때문이다
      • CPython : Python 코드를 컴파일하여 machine code로 바꾸고 그 다음에 interpreter(virtual machine)가 실행 ( Python 코드를 C언어로 바꾸는 것이 :x: )
      • Jython : python 코드를 java bytecode로 만들어 JVM에서 실행할 수 있도록 함

Q. Java와 C의 차이는?

  • C언어에 비해 Java가 느린 이유

    • C언어는 컴파일 시 코드를 모두 기계어로 직접 번역해서 바로 메모리에 올려두고 실행한다. 하지만 Java에서는 먼저 Bytecode로 컴파일을 한 뒤, 동적 할당 된 코드를 JVM의 Excution Engine이 번역해서 실행하게 된다.

      java_and_c

    • C언어에서는 동적 할당한 메모리를 개발자의 명령에 따라 즉시 해제하지만, Java는 직접 메모리를 다루지 않도록 되어 있기 때문에 이 작업을 GC(가비지 컬렉터)가 대신해준다. GC도 프로그램이기 때문에 메모리와 연산 작업을 동반한다.

    • 즉, 개발자가 편해지는 만큼 컴퓨터가 일을 더 해야하니 더 느릴 수밖에 없는 구조이다.

  • Compile 과정에서 차이

    • Java는 Link 과정이 없음, compiler가 바로 bytecode를 생성 그리고 이 bytecode file이 운영체제 위의 JVM에서 실행됨으로써 다양한 운영체제에서 독립적으로 사용이 가능
    • C의 경우, Compile 해서 생성된 실행 파일은 Platform에 종속적인 code가 있고 만약 Platform이 바뀐다면 다시 Compile해야 된다

결론

  • 프로그램 실행에 있어서 Python은 Java와 C언어에 비해 느리다
  • 하지만 Python이 Java와 C언어에 비해 제공하는 operation도 많고 가독성도 좋고 여러 방면에서 개발할 때 더 효율적인건 사실이다
  • 요즘같이 불명확성이 높은 상황에서 소프트웨어 개발하는 시간이 너무 길면 안된다
    • 가지고 있는 컨셉이 있으면 최대한 빨리 주요한 부분만 만들어서 제품을 내놓아야된다
    • 그리고 그 컨셉을 증명해야된다
    • End-user한테 가치를 전달할 수 있는 소프트웨어를 만드는게 중요하다
  • 그래서 차라리 Python을 가지고 먼저 만들고 출시해서 반응이 좋다면 Java 나 C 로 migration하면된다

《Reference》