C/C++ 이 파이썬 보다 속도가 빠르다고 한다. 그런데 얼마나 빠르냐고 물어보면 항상 답변은 비슷하다.

 

C++은 직접 컴파일 방식이고 기계어 명령어에 1대1 대응되니까 속도가 빨라.

 

파이썬은 인터프리터 방식이라 느려. 객체지향 언어는 데이터를 추상화하니까 느려.

 

등의 답변이 나올 것은 예상할 수 있다. 그런데 왜 컴파일 방식이 빨라요, 왜 C++은 기계어 명령어에 대응이 되고 파이썬은 안되요? 객체지향은 느린가요? 라고 꼬리에 꼬리를 무는 질문이 나오면 답변을 해도해도 끝이 없을 것 같다.

 

마치 리처드 파인만 박사의 왜라는 질문이 떠오른다.

 

리처드 파인만 자석은 왜 밀어내는가?

 

사실 기계어라는 것은 사람이 눈으로 읽는 코드에 지나지 않고 객체 지향의 추상화라는 것도 사람이 알아들을 수 있는 형태의 정보로 가공되서 텍스트나 그림으로 제공되는 것이다. 사람에겐 의미가 있다. 그런데 기계에겐 의미가 없다. 전류의 흐름 저장을 사람이 알 수 있는 기호로 표현하면 1과 0이 되는 것이지 실제 기계에게 1과 0이 무엇인지 모른다. 다만 그것을 처리하는 방법에 대하여 확실히 알고 있는 것이다. 그것도 엄청나게 정확하고 빠른 방식으로 알고 있다.

 

이 투박한 기계는 그야 말로 늘상 빛과 같은 속도로 움직(연산)이고 있는 것이다.

 

CPU가 동작하면서 바로 옆에서 전기가 흐르는 모습 그걸 옆에서 봤으면 좋겠는데 아,,, 볼 수 없다.

 

전자를 보는 현미경이 있다고 한다. 인텔은 원자를 조작하여 영화를 찍었다. (아래 유튜브) 댓글의 설명이 기가막히다. 4명의 연구원이 2주 동안 하루 18시간일해서 찍었다고 한다. 저것은 산소 원자라고 한다.

노동청에 고발감일세

 

전자를 보는 현미경이 있다고 한다 지구에 3대 (2015년)

 

This Microscope Can See Down to Individual Atoms

The UK's superSTEM facility got a new electron microscope with unprecedented resolution.

www.vice.com

심지어 인텔은 원자를 조작해서 영화를 찍었다. 세상에서 가장 작은 영화!

소년과 그의 원자. 진짜 원자라고 한다.

전자는 원자에 비하면 하염없이 작기 때문에 전자수준으로 정밀하게 측정되는 것까지는 알 수 없다. 지금 과학의 발전 속도에서 봤을 때 불가능해 보이지는 않는다. 머지않아 전자 영화도 볼 수 있기를 바란다.

 

C++과 파이썬의 속도차이를 이야기에 왜 원자 전자 이야기가 나오느냐? 그것은 사람들이 볼 수 없는 것들 경험할 수 없는 미지의 세계에 대한 이야기라서 할 수 있는 것이다. 컴퓨터 시스템은 전기로 작동하지만 전기 뿐 아니라 컴퓨터 내부에서 일어나고 있는 많은 것들(OS와 하드웨어 동작들도 마찬가지로)이 무언가 느껴질 만큼 보이지 않기 때문이다.

 

PC본체를 키면 컴퓨터가 돌고 있다는 것을 안다. 내부의 LED와 CPU 팬이 돌아가고 모니터에 화면이 들어오고 이 모든 것들은 컴퓨터 안에서 일어나고 있는 것이다.

 

표정 실화냐... (픽사베이 제공)

컴퓨터 내부의 수많은 동작들이 1초에 수억번도 넘게 일어나고 있어도 우리의 감각으로 느낄 수 있는 것은 표면적인 것들이다.

 

즉 전자가 일하는 것을 직접 볼 순 없지만 여러가지 방법으로 컴퓨터 동작의 원리를 경험할 수는 있다. 그리고 나머지는 인간의 뇌와 이성을 사용해서 짜 맞추는 것이다. 사람마다 이해하고 있는 범위는 다르다. 하지만 컴퓨터의 모든것을 알지 못하더라도 기계를 원하는 수준으로 컨트롤을 해서 무언가 의미있는 것을 창조하는 것은 가능하다. 컴퓨터를 가지고 일을 열심히 하면 된다.

 

그러면 일반인이 PC를 가지고 할 수 있는 것은 없을까? 꼭 연구소의 슈퍼컴퓨터를 봐야 알 수 있을까? 라고 생각해볼 수 있다. 이런 것은 하드웨어 벤치마킹을 하는 사람들이 잘한다. 고성능의 물리 엔진과 그래픽을 구현하는 최신 게임을 가지고 컴퓨터의 성능을 측정하는 것도 벌써 20년이 넘는 전통이 생겼다. 내 기억으로는 90년대 지금은 파산한 3Dfx라는 회사의 부두 그래픽 카드가 나왔을 때 3D 벤치마킹이라는 단어를 접했다.

부두 그래픽 카드

부두 그래픽 카드 리뷰

 

CPU 벤치마킹 사이트 Passmark software, 컴퓨터를 사기 전에 항상 들리는 곳이다.

 

PassMark Software - CPU Benchmarks

PassMark Software - CPU Benchmarks - Over 1 million CPUs and 1,000 models benchmarked and compared in graph form, updated daily!

www.cpubenchmark.net

3D 폴리곤 처리를 위한 부동소수점 계산 능력이 하드웨어의 척도라는 것도 처음 알았다. 그리고 그 때 그런 이야기도 했었다. 사담 후세인이 게임기술이 들어간 하드웨어를 사용해 미국에 발사할 탄도 미사일을 제작하고 있다는 등 (당시 미국은 중동과 항상 전쟁을 하고 있었다. 911 테러 이전에도)

 

파이썬과 C++로 연산능력 테스트하기

 

1.파이썬

 

하드웨어를 테스트 하기 위해서 고성능의 게임을 돌리는 것이 표준이지만 C++로도 테스트 할 수 있다. 물론 3D가속 성능을 테스트하기 위해서는 당연히 전용툴을 사용해야 하지만 CPU 연산 능력은 나름대로 해볼 수 있다. 전혀 거창하지 않은 내용이다.

 

우선 파이썬으로 테스트를 해본다. for루프를 사용해서 1부터 1천만까지 누산을 하며 시간을 측정해 볼 것이다. 1천만까지 누산이 끝나면 한번에 1천만번을 늘려서 시간을 측정한다. 총 시간이 10초를 넘어가면 루프를 종료시킬 것이다. 즉 10초 동안 얼마나 많은 수를 누산하는 테스트다. 

 

CPU 사양은 아래와 같다. 윈도우즈 10, 64비트이다. 4세대지만 당시 i7형이라 무리한 작업만 아니면 현재도 아주 나쁘지는 않은 사양이다. IDE는 파이참이다.

 

아래 코드는 for문의 수행시간을 평가한다. while 루프는 결과값을 출력하고 다음 작업으로 이동하기 때문에 시간 측정에 큰 영향을 미치지 않는다.

import time

def loop_sum(lcount):
    global sum
    for i in range(1, lcount + 1):
        sum += i

loop_count = 10000000
sum = 0
start = 0; end = 0

while True:
    start = time.time()
    loop_sum(loop_count)
    end = time.time()
    print("Count added : ",loop_count)
    print("Sum : ",sum)
    print("Time elapsed : ", round(end-start,3),"sec")
    if end-start > 10.0:
        break
    loop_count += 10000000

결과값은 아래와 같다. 10초동안 연산한 카운트의 개수는 9천만개 였다. 멀티태스킹이나 마우스를 건들거나 하면 OS에 인터럽트가 걸려서 결과가 달라지니까 작업 수행동안 다른 일을 하지 않았다.

Count added :  10000000
Sum :  50000005000000
Time elapsed :  1.119 sec
Count added :  20000000
Sum :  250000015000000
Time elapsed :  2.421 sec
Count added :  30000000
Sum :  700000030000000
Time elapsed :  3.507 sec
Count added :  40000000
Sum :  1500000050000000
Time elapsed :  4.866 sec
Count added :  50000000
Sum :  2750000075000000
Time elapsed :  5.866 sec
Count added :  60000000
Sum :  4550000105000000
Time elapsed :  7.432 sec
Count added :  70000000
Sum :  7000000140000000
Time elapsed :  8.262 sec
Count added :  80000000
Sum :  10200000180000000
Time elapsed :  9.775 sec
Count added :  90000000
Sum :  14250000225000000
Time elapsed :  10.662 sec

대체적으로 천만단위로 연산이 늘어나면 1초~ +@가 더 걸리는 것으로 나왔다. 파이썬 컴파일러의 정확한 작동 방식은  모른다. 허나 파이썬은 자료형을 자동으로 평가하기 때문에 그런 평가작업을 위한 시간들도 들어갔을 거라 예상한다.

 

어쨋든 정수 9천만개를 누산하는데 10초라는 것은 꽤 훌륭한 것 같다. 주판으로 한다고 하면,, 아니 너무 오버인가? 아직 주판을 쓰시던 세대가 살아있으니 그 분들은 기억하실지 모르지만 컴퓨터를 진지하게 배우는 분은 없겠지 생각이 들긴하다.

 

그럼 좀 현실로 돌아와서... 엑셀과 비교해도 압도적인 연산능력이다. 물론 재야의 엑셀 고수들은 별도의 스크립트나 프로그래밍으로 이 능력을 충분히 활용하고 있다고 믿는다. 결국 프로그래밍은 능력은 자동화와 많은 관련이 있다. 파이썬은 업무 자동화에 탁월한 능력을 가진 언어이다. 이 부분이 아마 전문가 들이 말하는 C언어가 성능이 좋아도 그걸 이끌어 내지 못하면 소용이 없다. 파이썬으로 더 쉽고 빠르게(사람이) 최대한 CPU의 파워를 이끌어 내는 것이 의미 있다는 말이라고 생각한다.

 

 

그 약간 드래곤볼의 잠재능력이 생각났다. 손오반이 마인부우에게 상대도 안됬는데 잠재능력 해방으로 부우를 압도한다. 그러니까 언어의 능력을 최대한 뽑아내는 것이 중요하다는 말이다.

손오반의 잠재능력 해방

2.C/C++

 

사실 문법적으로 C와 다를바 없는데 C++ 이라고 한 것은 어쨋든 C++ 은 C의 능력을 물려받은 계승자이기 때문이다.

 

C는 일단 파이썬하고 좀 다르다. 파이썬에서는 자료형이 없는데 여기서는 자료형을 선언해줘야 한다. 32비트 정수형으로는 unsigned로는 42억밖에 사용할 수 없으므로 처음부터 long long (64비트)를 사용했다. 64비트를 십진법으로 얼마나 큰 숫자인지 읽는 법도 쉽지않다. 여기서는 얼마나 누산할 수 있나 까지 평가했으므로 그냥 지수로도 나타냈다.

 

그리고 파이썬은 1천만 단위지만 C++에서는 연산의 개수를 1억 단위로 추가했다. 1천만은 사실 0.01초도 안 걸리기 때문에 측정의 의미가 없었다. 그게 벌써 차이가 난다. 파이썬은 1천만 단위로 시간이 느껴지는데 C++은 1억 단위로 가야한다. MinGW 32 비트 환경에서 측정해봤다. Visual Studio Code 터미널 사용.

 

역시 while 문은 함수 호출과 측정만 한다. do while 은 파이썬 문법에 없으니까 C++에서 사용한다. for문 내에서 지역변수 sum 하나와 i 하나를 사용해서 측정했다.

#include <tchar.h>
#include <iostream>
#include <ctime>

unsigned long long Adder(unsigned long long number){
    unsigned long long sum = 0;
    unsigned long long i;
    for(i=1; i<=number; i++){
        sum += i;
    }
    return sum;
}

int _tmain(int argc, _TCHAR * argv[])
{
    unsigned long long sum = 0, count = 100000000;
   clock_t st1, ed1;

do{
    st1 = clock();
    sum = Adder(count);
    ed1 = clock();
    printf("*\nCount added : %llu, ",count);
    printf("*Sum value : %llu, ",sum);
    printf("%e\n",(double)sum);
    printf("*Time elapsed: %d\n",ed1-st1);
    count += 100000000;
}while((ed1-st1)<10000);
    return 0;
}

결과를 보면 꽤나 쇼킹하다. 10초 동안에 42억개의 정수를 누산했다;;;; ㅎㄷㄷㄷㄷ 결과값을 보면 0000이니까 정확하게 나온 것 같다. 누산 결과는 8.8의 지수 10의 18승 정도된다. 파이썬이 9천만번 누산한 것과 비교하면 약 46배 정도 더 많은 계산을 했다. 같은 PC에서 이같은 차이는 큰 의미가 있는 것으로 보인다. 많은 이들이 파이썬이 느리다고 불평하는 이유가 있다. 동일한 조건 비교니까 확실한 차이를 보여준다.

 

Active code page: 65001

*---------------------------------*
       Here's what you got
==================================

*
Count added : 100000000, *Sum value : 5000000050000000, 5.000000e+015
*Time elapsed: 246
*
Count added : 200000000, *Sum value : 20000000100000000, 2.000000e+016
*Time elapsed: 496
*
Count added : 300000000, *Sum value : 45000000150000000, 4.500000e+016
*Time elapsed: 740
*
Count added : 400000000, *Sum value : 80000000200000000, 8.000000e+016
*Time elapsed: 986
*
Count added : 500000000, *Sum value : 125000000250000000, 1.250000e+017
*Time elapsed: 1229
*
Count added : 600000000, *Sum value : 180000000300000000, 1.800000e+017
*Time elapsed: 1481
*
Count added : 700000000, *Sum value : 245000000350000000, 2.450000e+017
*Time elapsed: 1715
*
Count added : 800000000, *Sum value : 320000000400000000, 3.200000e+017
*Time elapsed: 1974
*
Count added : 900000000, *Sum value : 405000000450000000, 4.050000e+017
*Time elapsed: 2241
*
Count added : 1000000000, *Sum value : 500000000500000000, 5.000000e+017
*Time elapsed: 2482
*
Count added : 1100000000, *Sum value : 605000000550000000, 6.050000e+017
*Time elapsed: 2806
*
Count added : 1200000000, *Sum value : 720000000600000000, 7.200000e+017
*Time elapsed: 2981
*
Count added : 1300000000, *Sum value : 845000000650000000, 8.450000e+017
*Time elapsed: 3214
*
Count added : 1400000000, *Sum value : 980000000700000000, 9.800000e+017
*Time elapsed: 3465
*
Count added : 1500000000, *Sum value : 1125000000750000000, 1.125000e+018
*Time elapsed: 3709
*
Count added : 1600000000, *Sum value : 1280000000800000000, 1.280000e+018
*Time elapsed: 3928
*
Count added : 1700000000, *Sum value : 1445000000850000000, 1.445000e+018
*Time elapsed: 4178
*
Count added : 1800000000, *Sum value : 1620000000900000000, 1.620000e+018
*Time elapsed: 4431
*
Count added : 1900000000, *Sum value : 1805000000950000000, 1.805000e+018
*Time elapsed: 4735
*
Count added : 2000000000, *Sum value : 2000000001000000000, 2.000000e+018
*Time elapsed: 4929
*
Count added : 2100000000, *Sum value : 2205000001050000000, 2.205000e+018
*Time elapsed: 5153
*
Count added : 2200000000, *Sum value : 2420000001100000000, 2.420000e+018
*Time elapsed: 5438
*
Count added : 2300000000, *Sum value : 2645000001150000000, 2.645000e+018
*Time elapsed: 5647
*
Count added : 2400000000, *Sum value : 2880000001200000000, 2.880000e+018
*Time elapsed: 5960
*
Count added : 2500000000, *Sum value : 3125000001250000000, 3.125000e+018
*Time elapsed: 6221
*
Count added : 2600000000, *Sum value : 3380000001300000000, 3.380000e+018
*Time elapsed: 6451
*
Count added : 2800000000, *Sum value : 3920000001400000000, 3.920000e+018
*Time elapsed: 6937
*
Count added : 2900000000, *Sum value : 4205000001450000000, 4.205000e+018
*Time elapsed: 7139
*
Count added : 3000000000, *Sum value : 4500000001500000000, 4.500000e+018
*Time elapsed: 7396
*
Count added : 3100000000, *Sum value : 4805000001550000000, 4.805000e+018
*Time elapsed: 8050
*
Count added : 3200000000, *Sum value : 5120000001600000000, 5.120000e+018
*Time elapsed: 7827
*
Count added : 3300000000, *Sum value : 5445000001650000000, 5.445000e+018
*Time elapsed: 8015
*
Count added : 3400000000, *Sum value : 5780000001700000000, 5.780000e+018
*Time elapsed: 8344
*
Count added : 3500000000, *Sum value : 6125000001750000000, 6.125000e+018
*Time elapsed: 8591
*
Count added : 3600000000, *Sum value : 6480000001800000000, 6.480000e+018
*Time elapsed: 8778
*
Count added : 3700000000, *Sum value : 6845000001850000000, 6.845000e+018
*Time elapsed: 8999
*
Count added : 3800000000, *Sum value : 7220000001900000000, 7.220000e+018
*Time elapsed: 9222
*
Count added : 3900000000, *Sum value : 7605000001950000000, 7.605000e+018
*Time elapsed: 9484
*
Count added : 4000000000, *Sum value : 8000000002000000000, 8.000000e+018
Count added : 4100000000, *Sum value : 8405000002050000000, 8.405000e+018
*Time elapsed: 9952
*
Count added : 4200000000, *Sum value : 8820000002100000000, 8.820000e+018
*Time elapsed: 10202

==================================

Press any key to continue . . .

시간은 밀리세컨드로 1000이 1초로 보면 된다.

 

작업도중에는 CPU 코어 4개가 거의 풀 스피드로 가동한다. 온도는 45도에서 60도 정도까지 올라간다.

(작업중인걸 감안하면 충분히 낮은 CPU 온도다)

 

물론 하나의 애플리케이션이 돌아가기 시작하면 CPU가 해야할일도 늘어나고 장치간의 병목현상도 생기는 등 다양한 변수가 실시간으로 발생한다. 지금이 무슨 단순한 CPU연산 능력만 가지고 컴퓨터의 성능을 측정하는 시대는 아니다. 요즘은 게임성능, 그래픽 작업 성능, 웹 성능 등 다양한 기준이 있다. 또 모든 것을 하나로 묶어 평가하는 것은 한계가 있다. 작업 용도에 맞고 그 일을 충실히 수행할 수 있다면 충분한 것이다.

 

하지만 그런것은 복잡하니까 좀 더 단순하고 직관적인 평가가 필요하다면 이런 방법도 가끔 해줄만 하다.

 

사실 컴퓨터를 업그레이드 할 시점이 좀 다가와서 이런 기록을 남기는 것도 있다. 업그레이드 하면 또 똑같은 것 할거니까 ㅋㅋㅋㅋ 그러면 구매 후 만족도가 높아진다. 어떤 CPU를 사도 4세대 i7보다는 나을 것이다. 코어수도 더 많고.

결국 목적이 그거였냐...

 

정수형 연산을 이렇게 해봤다면 부동소수점 연산도 해볼 수 있고 유튜브 동영상 시청중의 테스트도 해볼 수 있고 꽤 나름 많은 일들을 해볼 수 있다. for문과 while문만 가지고도 할 수 있다. 온라인 벤치마킹 사이트도 다 좋지만 결국 자기 자신이 사용하는 컴퓨터를 기준으로 봐야하니까 이런 시도가 나쁘지 않다.

 

이 글의 맨 처음의 설명이 아직도 100프로 이해가 되지는 않지만 적어도 이 정도 CPU로 테스트하면 파이썬과 C++의 효율 차이가 어느정도인가는 체감할 수 있었다. 흐음... 그런 차이가 있었구나. 가 이번의 결론이다.

 

*ps1 : C로 100억번까지 루프를 시도했으나 80억 정도 누산했을 때 오버플로우가 일어났다. 합산 값은 unsigned long long 으로 제대로 표시가 안되고 누산 시간은 기존과 달리 1억번당 0.3초가 아니라 훨씬 늘어나기 시작했다. 아무래도 오버플로우가 되면서 수정하기 위한 다른 작업이 들어간게 아닌가 싶다. C는 자료형에 따른 구간에 따른 속도 차이가 있다. long long 은 32비트 MinGW에서 최적화가 안되어 있을 것이다. int형이 더 빨랐으나 int 형의 계산 범위를 벗어나므로 long long 형을 써야 했다.

 

*ps2 : 코드는 비슷하게 하려했으니 내부 로직상 동일하지 않다. 최적화를 하면 결과가 조금 더 달라지겠지만 오늘 원한 유의미한 차이를 메꿀 정도일까는 의문이 든다. 파이썬은 for 문에 range를 많이 쓴다. range 가 iterable을 위한 built in 함수인데 이 보다 나은 옵션이 있을 거라 생각한다. 글쓴이도 파이썬에 대하여 아직 최적화까지는 다루지 않았다.

공유하기

facebook twitter kakaoTalk kakaostory naver band