C++와 Python 중 무엇을 먼저 배울까: 속도, 학습 난이도, 취업 시장 비교

이 글의 핵심

Python은 느리다는 말과 C++는 너무 어렵다는 말 사이에서 첫 언어를 정하지 못하는 경우가 많습니다. 이 글은 두 언어가 실제로 어디서 쓰이는지와 입문자가 부딪히는 어려움을 비교하고, 완전 초보, 게임·시스템 개발 지망, 빠른 취업 같은 상황별로 어떤 언어부터 시작할지 정리합니다.

한눈에 보는 비교표

항목C++Python
속도매우 빠름 (기계어로 컴파일)순수 Python 루프는 느림, NumPy 등 C 확장은 빠름
난이도어려움쉬움
메모리 관리RAII·스마트 포인터 (수동 new/delete도 가능)자동 (참조 카운팅 + 순환 GC)
실행 방식미리 컴파일 후 실행바이트코드로 바꿔 인터프리터가 실행
주 사용 분야게임 엔진, 시스템, 임베디드, 금융웹 백엔드, 데이터 분석, AI, 자동화
에러 발견 시점타입 에러 대부분 컴파일 시해당 줄이 실행될 때

속도 비교: 재귀 피보나치

fib(40) 실행 시간: C++ -O2 0.20초, C++ -O0 0.89초, Python 3.13 12.8초

그림: 실측 결과 — 같은 재귀 함수를 최적화한 C++는 0.2초, 최적화 없는 C++는 0.9초, CPython 3.13은 12.8초가 걸렸다. 최적화 옵션만으로도 4배 이상 차이가 난다.

// C++ (g++ -O2)
int fib(int n) {
    if (n <= 1) return n;
    return fib(n-1) + fib(n-2);
}
# CPython
def fib(n):
    if n <= 1:
        return n
    return fib(n-1) + fib(n-2)

fib(40)은 약 3억 3천만 번의 함수 호출을 합니다. 아래 환경(Xeon 2.1GHz VM, g++ 13.3, CPython 3.13.17)에서 직접 재 보니 -O2로 빌드한 C++는 0.20초, 최적화 없는 -O0 빌드는 0.89초, CPython은 12.8초가 걸렸습니다(중앙값). 같은 코드인데 컴파일 옵션만으로 4배, 언어 차이까지 합치면 60배 이상 벌어졌습니다. 정확한 배수는 CPU, 컴파일 옵션, Python 버전(3.11부터 인터프리터가 눈에 띄게 빨라졌습니다)에 따라 크게 달라지므로, 숫자보다 왜 차이가 나는지를 이해하는 편이 쓸모 있습니다.

C++의 fib는 컴파일되면 정수 레지스터 몇 개와 call 명령어 몇 개로 끝납니다. 같은 일을 CPython은 매번 이렇게 처리합니다. n - 1의 결과를 담을 정수 객체를 준비하고(-5256 범위의 작은 정수는 미리 만들어 둔 객체를 재사용하지만 그보다 크면 새로 할당합니다), fib라는 이름을 전역 이름 공간에서 찾고, 함수 호출용 프레임을 만들고, + 연산자가 두 객체의 타입을 확인한 뒤 알맞은 덧셈 함수를 호출합니다. C++에서 명령어 한두 개인 작업이 Python에서는 수십수백 개의 명령어가 되는 셈입니다. 이 차이는 반복문과 함수 호출이 많은 순수 Python 코드에서 가장 크게 드러나고, 실제 계산을 C로 짜인 라이브러리에 맡기는 코드에서는 거의 사라집니다.

그래서 “Python이 느리니 전부 C++로 다시 짜야 한다”는 결론은 대개 틀립니다. 대부분의 웹 서비스나 스크립트에서 시간은 데이터베이스 대기, 네트워크, 디스크에서 소비되고, 언어 자체의 실행 시간은 작은 비중입니다. 느리다고 느껴지면 먼저 프로파일러(python -m cProfile)로 어디서 시간이 쓰이는지 확인하고, 계산이 병목일 때만 그 부분을 NumPy나 C++ 확장으로 옮기는 것이 현실적인 순서입니다.

어떤 분야에서 쓰이는가

C++는 실행 속도와 메모리 배치를 직접 통제해야 하는 곳에서 주로 쓰입니다. 게임 엔진이 대표적인데, Unreal Engine은 게임 코드까지 C++로 작성하고, Unity는 엔진 내부가 C++이며 게임 스크립트는 C#으로 씁니다. 운영체제, 드라이버, 임베디드 펌웨어 같은 시스템 소프트웨어와, 지연 시간이 수익과 직결되는 초단타 매매(HFT) 시스템, 브라우저나 데이터베이스 같은 기반 소프트웨어도 C++의 주 무대입니다.

Python은 개발 속도와 라이브러리 생태계가 중요한 곳에서 강합니다. Django, Flask, FastAPI로 만드는 웹 백엔드, pandas·NumPy를 쓰는 데이터 분석, PyTorch·TensorFlow로 모델을 학습하고 서빙하는 AI 분야, 업무 자동화와 크롤링, 아이디어를 빨리 검증해야 하는 프로토타입 개발이 대표적입니다.

분야C++Python일반적인 선택
웹 백엔드가능하지만 복잡Django/Flask/FastAPIPython
게임 개발Unreal, 엔진 개발Pygame (제한적)C++ (Unity는 C#)
AI/ML추론 엔진·커널 개발PyTorch/TensorFlowPython
시스템 프로그래밍주력 언어부적합C++ (C, Rust와 함께)
데이터 분석가능하지만 번거로움pandas/NumPyPython
임베디드주력 언어MicroPython (제한적)C/C++
초단타 매매주력 언어전략 연구·백테스트실행은 C++, 연구는 Python
업무 자동화·크롤링번거로움requests/BeautifulSoup/ScrapyPython
모바일 앱NDK로 일부 모듈Kivy (제한적)둘 다 주력 아님 (Kotlin, Swift)

게임 개발이 무조건 C++인 것도 아닙니다. 대형 3D 게임이나 엔진 개발은 C++가 사실상 필수지만, 인디 게임은 Unity(C#)나 Godot(GDScript)이 많이 쓰이고, 게임 서버 백엔드나 사내 툴은 Python으로 만드는 경우도 흔합니다.

학습 난이도

C++가 초반에 어려운 이유는 문법 자체보다 프로그램을 실행하기까지 알아야 할 것이 많다는 데 있습니다. 컴파일러 설치, 헤더와 소스 파일의 분리, 링크 에러, 빌드 도구(CMake 등), 그리고 값·참조·포인터의 차이와 객체 수명을 처음부터 신경 써야 합니다. 게다가 배열 범위를 넘어가거나 해제된 메모리를 쓰는 실수를 해도 에러 메시지 없이 “가끔 이상하게 동작”하는 미정의 동작으로 나타나기 때문에, 초보자가 원인을 스스로 찾기가 어렵습니다. 반대로 이 과정을 거치면 메모리와 CPU가 실제로 어떻게 일하는지에 대한 감각이 생기고, 이는 나중에 어떤 언어를 쓰든 성능 문제를 이해하는 바탕이 됩니다.

Python의 어려움은 뒤늦게 옵니다. 타입을 선언하지 않으므로 None이 들어갈 수 있는 변수에 메서드를 호출하는 실수(AttributeError: 'NoneType' object has no attribute ...)가 그 줄이 실제로 실행될 때까지 드러나지 않습니다. 작은 스크립트에서는 문제가 안 되지만, 코드가 수천 줄로 커지면 타입 힌트와 mypy 같은 검사 도구, 테스트가 C++ 컴파일러가 해 주던 역할을 대신해야 합니다. 또 가상환경(venv)과 패키지 버전 관리를 모르면 “내 컴퓨터에서는 되는데 서버에서 ModuleNotFoundError가 난다”는 문제를 반복해서 겪게 됩니다.

# 타입 힌트: 실행에는 영향이 없지만 mypy와 IDE가 실수를 미리 잡아 준다
def add(a: int, b: int) -> int:
    return a + b

C++로 시작했다가 포인터와 메모리 관리에서 막히는 경우가 많은데, 이는 오래된 교재가 new/delete로 배열을 직접 관리하는 방식부터 가르치는 탓도 있습니다. C++11 이후의 표준 방식은 std::vector, std::string, 스마트 포인터처럼 메모리를 스스로 해제하는 타입을 기본으로 쓰는 것입니다.

// 오래된 방식: delete[]를 빠뜨리면 누수, 두 번 하면 미정의 동작
int* ptr = new int[100];
// ... 사용 ...
delete[] ptr;

// C++11 이후 표준 방식: 스코프를 벗어나면 자동으로 해제
std::vector<int> vec(100);

C++를 배운다면 C++11 이상을 다루는 자료로 시작하고, 원시 포인터와 new/delete는 표준 컨테이너와 스마트 포인터에 익숙해진 뒤에 배우는 편이 덜 막힙니다.

상황별 추천

프로그래밍이 완전히 처음이고 목표가 아직 정해지지 않았다면 Python으로 시작하는 편이 낫습니다. 문법이 간단해 첫 주부터 파일 처리나 웹 요청처럼 눈에 보이는 결과를 만들 수 있고, 이 경험이 꾸준히 배우는 동력이 됩니다. 웹이나 데이터 분야로 빨리 취업하려는 경우도 Python이 수요와 학습 속도 면에서 유리합니다.

게임 엔진, 임베디드, 시스템 소프트웨어처럼 목표가 분명하면 처음부터 C++로 가는 것이 돌아가지 않는 길입니다. 이 분야의 면접과 실무가 메모리 모델, 객체 수명, 성능 분석을 깊이 다루기 때문에, 다른 언어로 시작해도 결국 이 부분을 다시 배워야 합니다.

두 언어를 동시에 시작하는 것은 권하지 않습니다. 기초 개념(변수, 조건문, 함수, 자료구조)을 한 언어로 확실히 익힌 뒤 두 번째 언어를 배우면, 두 번째 언어는 문법과 차이점만 익히면 되므로 훨씬 빨리 배울 수 있습니다. 장기적으로는 두 언어를 함께 쓰는 개발자가 많고, Python으로 전체 흐름을 짜고 병목만 C++로 옮기는 조합은 데이터·AI 분야에서 흔한 구성입니다.

graph TD
    A[프로그래밍 시작] --> B{목표가 정해졌나요?}
    B -->|웹/AI/데이터| C[Python으로 시작]
    B -->|게임 엔진/시스템/임베디드| D[C++로 시작]
    B -->|아직 모름| C
    C --> E[작은 프로젝트 완성]
    D --> F[작은 프로젝트 완성]
    E --> G{성능이나 시스템에 관심?}
    G -->|예| H[C++ 추가]
    G -->|아니오| I[Python 심화]
    F --> J{스크립팅·데이터 도구가 필요?}
    J -->|예| K[Python 추가]
    J -->|아니오| L[C++ 심화]

같은 작업을 두 언어로

파일에서 숫자를 읽어 합계 계산

#include <iostream>
#include <fstream>
#include <vector>

int main() {
    std::ifstream file("numbers.txt");
    std::vector<int> numbers;
    int num;

    while (file >> num) {
        numbers.push_back(num);
    }

    int sum = 0;
    for (int n : numbers) {
        sum += n;
    }

    std::cout << "합계: " << sum << std::endl;
    return 0;
}
with open('numbers.txt') as f:
    numbers = [int(line) for line in f]

total = sum(numbers)
print(f"합계: {total}")

C++ 버전은 줄 수가 많고 타입을 명시해야 하며 컴파일이 필요하지만, Python 버전은 몇 줄로 끝나고 바로 실행됩니다.

줄 수보다 흥미로운 차이는 잘못된 입력을 만났을 때의 동작입니다. 파일 중간에 빈 줄이나 abc 같은 글자가 섞여 있으면, Python 버전은 ValueError: invalid literal for int() with base 10: '\n' 같은 오류를 내며 즉시 멈춥니다. C++ 버전의 while (file >> num)은 abc를 만나 읽기에 실패하는 순간 조용히 루프를 끝내고, 그때까지의 합계를 정상 결과처럼 출력합니다(빈 줄은 공백으로 취급되어 건너뜁니다). 파일이 아예 없어도 ifstream은 예외를 던지지 않아서 “합계: 0”이 나옵니다. C++에서 이런 경우를 잡으려면 if (!file)로 열기를 확인하고, 루프가 끝난 뒤 file.eof()인지 검사해야 합니다. 또 int sum은 숫자가 크면 오버플로(미정의 동작)가 나지만 Python의 정수는 크기 제한이 없습니다. “Python은 쉬운 대신 대충”이라는 인상과 달리, 기본 동작은 오히려 Python 쪽이 실수를 더 시끄럽게 알려 주는 경우가 많습니다.

웹 서버

// C++ (Crow 프레임워크)
#include "crow.h"

int main() {
    crow::SimpleApp app;

    CROW_ROUTE(app, "/")([]() {
        return "Hello World!";
    });

    app.port(8080).multithreaded().run();
}
# Python (Flask)
from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello():
    return 'Hello World!'

if __name__ == '__main__':
    app.run(port=8080)

C++ 코드도 짧아 보이지만, Crow 라이브러리를 받아 CMake로 빌드하고 의존성(Asio 등)을 맞추는 과정이 필요합니다. Python은 pip install flask 후 바로 실행됩니다. 웹 서버는 대부분 데이터베이스와 네트워크를 기다리는 시간이 길어서 언어 속도 차이가 결과에 잘 드러나지 않습니다. C++ 웹 서버는 초저지연이 필요한 게임 서버나 트레이딩 게이트웨이처럼 특수한 경우에 선택되고, 일반적인 API 서버는 Python, Go, Java, Node.js 같은 언어로 만드는 것이 개발·운영 비용 면에서 유리합니다.

데이터 분석

import pandas as pd
import matplotlib.pyplot as plt

df = pd.read_csv('sales.csv')
monthly_sales = df.groupby('month')['sales'].sum()
monthly_sales.plot(kind='bar')
plt.show()

같은 일을 C++로 하려면 CSV 파싱, 그룹별 집계, 그래프 출력을 각각 별도 라이브러리로 해결해야 하고, “한 줄 바꿔 보고 결과를 바로 확인”하는 탐색적 분석 흐름(Jupyter 노트북)에도 맞지 않습니다. 흥미로운 점은 pandas와 NumPy의 핵심 연산 자체는 C와 C++로 구현되어 있다는 것입니다. 데이터 분석에서 Python이 이기는 이유는 실행 속도가 아니라, 빠른 네이티브 코드를 쉬운 문법으로 조합할 수 있게 해 주는 생태계입니다.

Python이 느리다는 걱정과 GIL

CPython에는 GIL(Global Interpreter Lock)이 있어서, 스레드를 여러 개 만들어도 순수 Python 코드는 한 번에 한 스레드만 실행됩니다. 네트워크나 파일을 기다리는 동안에는 GIL이 풀리므로 I/O 위주 작업은 스레드로도 충분히 병렬화되지만, CPU 계산을 여러 코어로 나누려면 multiprocessing을 쓰거나 GIL을 풀어 주는 C 확장(NumPy 등)에 맡겨야 합니다. Python 3.13부터 GIL을 끈 free-threaded 빌드가 별도로 제공되기 시작했지만, 기본 배포판은 여전히 GIL이 있는 빌드입니다.

웹 서버는 네트워크 I/O가 병목이고, 데이터 분석과 AI는 NumPy·PyTorch 내부의 C/C++ 코드가 계산을 맡으므로, 대부분의 경우 Python의 속도는 실제 문제가 되지 않습니다.

성능 최적화

Python 코드 빠르게 만들기

# 순수 Python 루프
result = []
for i in range(1000000):
    result.append(i * 2)

# NumPy 벡터화
import numpy as np
result = np.arange(1000000) * 2

NumPy 버전은 루프가 Python 인터프리터가 아니라 C 코드 안에서 돌기 때문에 크게 빨라집니다. 다만 NumPy 배열의 원소를 하나씩 for로 접근하면 원소마다 Python 객체를 만들어야 해서 오히려 리스트보다 느려질 수 있으므로, 배열 전체에 한 번에 연산하는 벡터화 스타일로 써야 이득이 있습니다.

result = [i * 2 for i in range(1000)]

리스트 컴프리헨션은 매번 result.append 속성을 찾아 호출하는 비용이 줄어 같은 for 루프보다 조금 빠릅니다. 다만 그 차이는 알고리즘이나 자료구조를 바꾸는 것에 비하면 작습니다.

계산 병목이 NumPy로 표현되지 않으면 그 부분만 C++로 작성해 pybind11로 Python에 노출할 수 있습니다.

#include <pybind11/pybind11.h>
#include <cstdint>

std::int64_t sum_of_squares(std::int64_t n) {
    std::int64_t sum = 0;
    for (std::int64_t i = 0; i < n; ++i) {
        sum += i * i;
    }
    return sum;
}

PYBIND11_MODULE(my_module, m) {
    m.def("sum_of_squares", &sum_of_squares);
}
import my_module
print(my_module.sum_of_squares(1_000_000))

이렇게 하면 계산 자체가 기계어로 실행됩니다. 주의할 점은 두 가지입니다. 첫째, Python과 C++ 경계를 넘는 호출에도 비용이 있어서, 이 함수를 원소마다 한 번씩 백만 번 호출하면 경계 비용이 이득을 삼켜 버립니다. 데이터를 한 번에 넘기고 루프는 C++ 안에서 돌게 설계해야 합니다. 둘째, 정수 범위입니다. 위 코드를 int로 작성하면 제곱합이 약 21억을 넘는 n≈1,900부터 오버플로가 나는데, Python 쪽에서는 정수가 자동으로 커지는 데 익숙하기 때문에 갑자기 나타나는 음수 결과를 예상하지 못합니다. 그래서 위 예시는 64비트 정수를 썼고, 그래도 n이 수백만을 넘으면 64비트 범위도 넘어서므로 입력 범위를 확인해야 합니다.

C++ 코드 빠르게 만들기

g++ -o program program.cpp                   # 최적화 없음 (-O0)
g++ -O2 -o program program.cpp               # 일반적인 릴리스 빌드
g++ -O3 -march=native -o program program.cpp # 빌드한 CPU 전용 최적화

최적화 없는 -O0 빌드는 디버깅용이라 C++라도 느립니다. 성능을 비교할 때는 반드시 -O2 이상으로 빌드해야 공정합니다. -march=native는 빌드한 CPU의 명령어 세트를 쓰므로, 다른 머신에 배포할 바이너리에는 쓰면 안 됩니다. 구형 CPU에서 Illegal instruction으로 종료될 수 있습니다.

#include <numeric>

int sum = std::accumulate(vec.begin(), vec.end(), 0);

std::accumulate 같은 표준 알고리즘은 최적화 빌드에서 직접 쓴 루프와 사실상 같은 기계어가 되므로 속도 차이를 기대할 것은 아닙니다. 장점은 의도가 분명하고 인덱스 실수가 줄어든다는 점입니다. 흔한 함정으로, vector<double>을 합칠 때 초기값을 0으로 주면 누적값의 타입이 int가 되어 소수점이 잘립니다. 초기값을 0.0으로 줘야 합니다.

벤치마크 수치를 볼 때 주의할 점

인터넷에서 보는 “C++이 N배 빠르다”는 표는 대부분 특정 CPU, 특정 컴파일 옵션, 특정 코드에서 측정한 값입니다. 예를 들어 정수 100만 개 정렬은 Python의 sorted()도 내부적으로 C로 구현된 Timsort를 쓰므로, 차이는 주로 Python 정수 객체를 비교하는 비용에서 나옵니다. NumPy의 np.sort()는 원시 정수 배열을 정렬하므로 C++에 훨씬 가까워집니다. 자신의 작업을 판단하려면 비슷한 크기의 데이터로 직접 time이나 timeit으로 재 보는 것이 가장 정확합니다.

취업 시장과 전망

Python 개발자 채용에서는 실제로 배포한 웹 서비스나 데이터 분석 결과물이 포트폴리오로 쓰이고, Django/FastAPI, SQL, Git, Docker, 클라우드 기초가 자주 요구됩니다. 지원자가 많은 분야라 언어 자체보다 데이터베이스 설계나 배포 경험 같은 주변 역량으로 차별화해야 하는 경우가 많습니다. Python만으로도 백엔드, 데이터 분석, ML 엔지니어링, DevOps 같은 직군에 충분히 지원할 수 있습니다.

C++ 개발자 채용에서는 게임 클라이언트, 네트워크 서버, 임베디드 펌웨어처럼 성능과 메모리를 다룬 프로젝트가 포트폴리오로 쓰이고, STL, 메모리 모델, 멀티스레딩, 디버거·프로파일러 사용, CMake가 자주 요구됩니다. 채용 수는 적은 편이지만 진입 장벽이 높아 경쟁자도 적은 편이며, 면접에서는 가상 함수 테이블, 스마트 포인터, 이동 의미론 같은 언어 내부 동작 질문이 자주 나옵니다.

전망도 분야에 따라 다릅니다. Python은 AI 모델을 학습·서빙하는 코드의 기본 언어이고 데이터 분석, 자동화, 웹 백엔드에서 꾸준히 쓰입니다. C++는 게임 엔진, 브라우저, 데이터베이스, 컴파일러 같은 기반 소프트웨어의 주력 언어이며, AI 분야에서도 PyTorch 내부, 추론 엔진, GPU 커널 주변 코드는 C++로 작성됩니다. 메모리 안전성 문제로 일부 신규 시스템 코드가 Rust로 옮겨 가는 흐름이 있지만, 이미 쌓인 C++ 코드베이스가 매우 커서 유지·개발 수요는 오래 이어질 것이라는 시각이 일반적입니다.

Instagram은 Django로 서비스를 키운 사례로 자주 언급되지만, 이런 대형 서비스도 성능이 중요한 부분은 캐시, 별도 서비스, C 확장 등으로 보완합니다. “Python만으로 충분하다”기보다 “대부분의 코드는 Python으로, 병목만 다른 수단으로”가 정확한 이해입니다. 연봉 역시 언어보다 회사 규모와 도메인(게임, 금융, 반도체, 웹 서비스)에 따라 훨씬 크게 갈리므로, 언어만 보고 판단하지 않는 것이 좋습니다.