V vs Python: 누가 더 빠른가? 벤치마크 대결
"V가 Python보다 100배 빠르다" — V 공식 사이트에서 이런 주장을 볼 수 있다. 정말 그럴까? 이번 편에서는 같은 문제를 V와 Python으로 풀고, 실행 시간을 직접 측정해본다. 그리고 "속도가 전부인가?"라는 질문에도 답해본다.
왜 V와 Python을 비교하나?
두 언어는 정반대의 철학을 가지고 있다.
| 항목 | V | Python |
|---|---|---|
| 유형 | 컴파일 언어 | 인터프리터 언어 |
| 타입 | 정적 타입 | 동적 타입 |
| 실행 방식 | 기계어로 번역 후 실행 | 한 줄씩 해석하며 실행 |
| 메모리 관리 | 수동/자동 (autofree) | 가비지 컬렉터 |
| 주요 용도 | 시스템, CLI, 웹 서버 | 데이터 과학, 웹, 자동화, AI |
비유하자면, V는 전용 번역본을 미리 만들어두는 것이고, Python은 통역사가 실시간으로 번역하는 것이다. 미리 번역해 놓으면 읽기가 빠르지만, 번역 과정 자체에 시간이 필요하다. 통역은 바로 시작할 수 있지만, 매번 통역 과정이 필요해서 느리다.
V (컴파일 언어):
소스 코드 ──→ [컴파일] ──→ 기계어 실행 파일 ──→ CPU가 직접 실행
(1번만) (매우 빠르게)
Python (인터프리터 언어):
소스 코드 ──→ [인터프리터가 한 줄씩 읽고 실행]
(매번 해석 필요 → 느림)
벤치마크 1: 피보나치 수열 (CPU 연산)
피보나치 수열은 순수 CPU 연산 성능을 측정하는 고전적인 벤치마크다. 재귀 호출이 기하급수적으로 늘어나서, 언어의 함수 호출 속도를 직접적으로 비교할 수 있다.
V 코드
import time
fn fib(n int) int {
if n <= 1 {
return n
}
return fib(n - 1) + fib(n - 2)
}
fn main() {
n := 40
sw := time.new_stopwatch()
result := fib(n)
elapsed := sw.elapsed()
println('fib(${n}) = ${result}')
println('소요 시간: ${elapsed.milliseconds()}ms')
}
Python 코드
import time
def fib(n):
if n <= 1:
return n
return fib(n - 1) + fib(n - 2)
n = 40
start = time.time()
result = fib(n)
elapsed = time.time() - start
print(f"fib({n}) = {result}")
print(f"소요 시간: {elapsed * 1000:.0f}ms")
결과 비교
| 언어 | fib(40) | 소요 시간 | 배율 |
|---|---|---|---|
V (-prod) | 102334155 | ~380ms | 1× |
| Python 3.12 | 102334155 | ~25,000ms | ~66× |
같은 답(102334155)을 계산하는데, V는 약 0.4초, Python은 약 25초가 걸린다. V가 약 66배 빠르다.
왜 이런 차이가 날까?
V:
fib() 함수 호출 → CPU가 기계어 명령어를 직접 실행
오버헤드: 거의 없음
Python:
fib() 함수 호출 → 인터프리터가 바이트코드를 해석
→ 객체 생성 → 타입 검사 → 참조 카운팅 → 실행
오버헤드: 매 호출마다 발생
재귀 피보나치에서 fib(40)은 함수를 약 3.3억 번 호출한다. V는 각 호출이 기계어 수준이지만, Python은 매 호출마다 인터프리터 오버헤드가 쌓인다.
벤치마크 2: 반복문 (루프 성능)
대량의 숫자를 반복 처리하는 성능을 비교해보자.
V 코드
import time
fn sum_to(n i64) i64 {
mut total := i64(0)
for i := i64(0); i < n; i++ {
total += i
}
return total
}
fn main() {
n := i64(1_000_000_000) // 10억
sw := time.new_stopwatch()
result := sum_to(n)
elapsed := sw.elapsed()
println('합계: ${result}')
println('소요 시간: ${elapsed.milliseconds()}ms')
}
Python 코드
import time
def sum_to(n):
total = 0
for i in range(n):
total += i
return total
n = 1_000_000_000 # 10억
start = time.time()
result = sum_to(n)
elapsed = time.time() - start
print(f"합계: {result}")
print(f"소요 시간: {elapsed * 1000:.0f}ms")
결과 비교
| 언어 | 10억 합계 | 소요 시간 | 배율 |
|---|---|---|---|
V (-prod) | 499999999500000000 | ~500ms | 1× |
| Python 3.12 | 499999999500000000 | ~45,000ms | ~90× |
10억 번 반복에서 V가 약 90배 빠르다. 루프 한 바퀴당 V는 CPU 명령 몇 개, Python은 인터프리터 처리 과정이 필요하기 때문이다.
벤치마크 3: JSON 파싱 (실전 작업)
실전에서 자주 하는 JSON 파싱 성능을 비교해보자. 큰 JSON 배열을 파싱하는 시간을 측정한다.
V 코드
import time
import json
struct Item {
id int
name string
value f64
active bool
}
fn main() {
// 10만 개의 JSON 아이템 문자열 생성
mut items_json := '['
for i in 0 .. 100_000 {
if i > 0 { items_json += ',' }
items_json += '{"id":${i},"name":"item_${i}","value":${f64(i) * 1.5},"active":${i % 2 == 0}}'
}
items_json += ']'
// 파싱 시간 측정
sw := time.new_stopwatch()
items := json.decode([]Item, items_json) or {
println('파싱 실패')
return
}
elapsed := sw.elapsed()
println('파싱된 아이템: ${items.len}개')
println('첫 번째: ${items[0].name}')
println('마지막: ${items[items.len - 1].name}')
println('소요 시간: ${elapsed.milliseconds()}ms')
}
Python 코드
import time
import json
# 10만 개의 JSON 아이템 문자열 생성
items_list = [
{"id": i, "name": f"item_{i}", "value": i * 1.5, "active": i % 2 == 0}
for i in range(100_000)
]
items_json = json.dumps(items_list)
# 파싱 시간 측정
start = time.time()
items = json.loads(items_json)
elapsed = time.time() - start
print(f"파싱된 아이템: {len(items)}개")
print(f"첫 번째: {items[0]['name']}")
print(f"마지막: {items[-1]['name']}")
print(f"소요 시간: {elapsed * 1000:.0f}ms")
결과 비교
| 언어 | 10만 JSON 아이템 파싱 | 소요 시간 | 배율 |
|---|---|---|---|
V (-prod) | 구조체 배열로 변환 | ~120ms | 1× |
| Python 3.12 | dict 리스트로 변환 | ~280ms | ~2.3× |
JSON 파싱에서는 차이가 2~3배 수준으로 줄어든다. 왜 일까?
Python의 json 모듈은 C로 작성되어 있다. Python 자체는 느리지만, 핵심 라이브러리의 내부 구현이 C이기 때문에 성능 격차가 작다. 이것이 Python 생태계의 강점이다 — 자주 쓰는 라이브러리의 핵심은 이미 C로 최적화되어 있다.
💡 이 결과에서 배우는 것: 순수 계산에서는 V가 압도적이지만, I/O나 라이브러리 의존 작업에서는 격차가 줄어든다. "V가 Python보다 100배 빠르다"는 순수 계산 기준의 이야기다.
왜 이런 차이가 나는가?
컴파일 언어 vs 인터프리터 언어
두 언어의 실행 방식 차이를 한 장의 그림으로 정리하면 이렇다.
V (컴파일 언어):
┌──────────┐ ┌──────────┐ ┌──────────┐
│ 소스 코드 │────→│ C 코드 │────→│ 기계어 │
│ (.v) │ │ (자동생성) │ │ (CPU 직접) │
└──────────┘ └──────────┘ └──────────┘
1번만 변환 매번 빠르게 실행
Python (인터프리터):
┌──────────┐ ┌──────────────────────────────┐
│ 소스 코드 │────→│ 인터프리터가 매번 해석+실행 │
│ (.py) │ │ 타입 검사, 객체 생성, GC 등 │
└──────────┘ └──────────────────────────────┘
실행할 때마다 오버헤드 발생
속도 차이의 핵심 원인
| 요인 | V | Python | 영향 |
|---|---|---|---|
| 타입 검사 | 컴파일 시 1번 | 실행 중 매번 | 큰 차이 |
| 메모리 할당 | 스택 기반 (빠름) | 힙+객체 (느림) | 큰 차이 |
| 함수 호출 | CPU 명령 직접 | 인터프리터 경유 | 큰 차이 |
| 가비지 컬렉션 | 가벼움/autofree | 참조 카운팅+GC | 중간 차이 |
| 최적화 | C 컴파일러 최적화 | JIT 없음 (CPython) | 큰 차이 |
그런데... 속도가 전부인가?
여기까지만 보면 "V가 무조건 좋은 거 아닌가?"라고 생각할 수 있다. 하지만 현실은 다르다.
Python이 여전히 강한 이유
| 항목 | Python의 강점 |
|---|---|
| 생태계 | NumPy, Pandas, TensorFlow, Django, Flask... |
| 학습 곡선 | 프로그래밍 입문자에게 가장 쉬운 언어 중 하나 |
| AI/ML | 사실상 유일한 선택지 (PyTorch, Hugging Face 등) |
| 데이터 과학 | Jupyter Notebook, Matplotlib, Seaborn |
| 자동화 | 시스템 관리, 웹 스크래핑, 스크립팅 |
| 인력 풀 | 개발자가 매우 많음, 채용이 쉬움 |
| 프로토타입 | 빠르게 만들고 빠르게 검증 |
Python이 느린 건 사실이지만, 대부분의 프로덕션 Python 코드에서 병목은 CPU 연산이 아니라 네트워크 I/O나 데이터베이스 쿼리다. 웹 서버가 API 요청을 처리할 때, 대부분의 시간은 데이터베이스 응답을 기다리는 데 쓰인다. 이런 상황에서 언어 자체의 속도는 크게 중요하지 않다.
"적합한 도구를 고르자"
┌─────────────────────────────────────────────────┐
│ 언어 선택 가이드 │
├─────────────────────────────────────────────────┤
│ │
│ CPU 집약적 작업 │ V, C, Rust, Go │
│ (영상 처리, 게임 엔진) │ │
│ │ │
│ 웹 백엔드 │ Go, V, Python, Node │
│ (API 서버) │ │
│ │ │
│ AI / 머신러닝 │ Python (사실상 독점) │
│ │ │
│ 데이터 분석 │ Python, R │
│ │ │
│ CLI 도구 │ V, Go, Rust │
│ │ │
│ 빠른 프로토타입 │ Python, V │
│ │ │
│ 임베디드 / IoT │ V, C, Rust │
│ │ │
└─────────────────────────────────────────────────┘
벤치마크 전체 요약
| 벤치마크 | V | Python | 배율 | 차이 원인 |
|---|---|---|---|---|
| 피보나치(40) | 380ms | 25,000ms | ~66× | 함수 호출 오버헤드 |
| 10억 루프 | 500ms | 45,000ms | ~90× | 루프 인터프리터 오버헤드 |
| JSON 파싱 | 120ms | 280ms | ~2.3× | Python json이 C 구현 |
- 순수 CPU 연산: V가 50~100배 빠르다
- 라이브러리 의존 작업: 격차가 2~5배로 줄어든다
- 실전 웹 서버: I/O 대기 시간이 대부분이므로 차이가 더 줄어든다
핵심 결론
"V가 더 빠른가?" → Yes, 순수 연산에서 수십 배 빠르다.
"그래서 Python 대신 V를 써야 하나?" → 상황에 따라 다르다. 속도가 중요한 CLI 도구, 시스템 프로그래밍, 고성능 서버에서는 V가 좋은 선택이다. AI/ML, 데이터 과학, 빠른 프로토타입에서는 여전히 Python이 더 적합하다.
📝 정리
- [x] 순수 연산 — V가 Python보다 50~100배 빠르다 (피보나치, 루프)
- [x] 라이브러리 작업 — 격차가 2~5배로 줄어든다 (Python 핵심 라이브러리가 C 구현)
- [x] 원인 — 컴파일(1번 번역) vs 인터프리터(매번 해석), 타입 검사·메모리·함수 호출 오버헤드
- [x] Python의 강점 — 생태계(AI/ML/데이터), 학습 용이성, 풍부한 인력 풀
- [x] V의 강점 — CPU 연산 속도, 작은 바이너리, 크로스 플랫폼, 간결한 문법
- [x] 선택 기준 — 속도가 핵심이면 V, 생태계가 핵심이면 Python
- [x] 속도가 전부는 아니다 — 대부분의 실전 프로그램은 I/O가 병목
다음 편 예고
실전 8편: 채팅 서버 — 동시성 프로그래밍 실습
비교는 여기까지! 마지막 실전으로, 문법 시리즈 10편에서 배운
spawn과 채널을 실전에 적용한다. TCP 소켓으로 클라이언트를 받고, 메시지를 모든 접속자에게 브로드캐스트하는 터미널 기반 멀티유저 채팅 서버를 만든다.