Files
five/docs/go-performance-ko.md
Charles KWON OhJun 59568f3301 Five v0.9 — Harbour + Go fusion language
- Compiler: PP → Lexer → Parser → Analyzer → Gengo pipeline
- Parser: 232/236 (98%) Harbour compatibility, registry-based dispatch
- RTL: 351 Harbour-compatible functions
- RDD: DBF/NTX/CDX engines with Rushmore bitmap optimization
- Go Interop: IMPORT + pkg.Func() + obj:Method() with FastPath (15M calls/sec)
- HB_FUNC API: Full Harbour C API compatible Go bridge
- Concurrency: SPAWN/LAUNCH/GOROUTINE, <-, WATCH, PARALLEL FOR, ASYNC/AWAIT
- Extensions: Multi-return, DEFER, Slice, f-string, Nil-safe ?:, CONST
- Macro Compiler: Runtime AST parsing and evaluation
- Debugger: TUI debugger with source display, breakpoints, stepping
- FRB: Native + Pcode dual mode runtime binary
- Tests: 13 packages ALL PASS

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 09:41:50 +09:00

176 lines
6.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Five Go Interop Performance
## 핵심 요약
PRG에서 Go 함수를 호출할 때, Five는 자동으로 **3단계 최적화**를 적용합니다.
개발자가 코드를 바꿀 필요 없음 — gengo가 알아서 최적 경로를 선택.
## 벤치마크 결과 (Intel Ultra 7 255H)
```
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Function Direct Go Reflect FastPath 개선
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
strings.ToUpper 34ns 243ns 66ns 3.7x
strings.Contains 3ns 218ns 19ns 11.7x
strings.ReplaceAll 43ns 339ns 77ns 4.4x
math.Sqrt 0.1ns 175ns 16ns 11.0x
obj:Method() — 416ns 233ns 1.8x
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
메모리 할당 1회 7~9회 1~3회 3x 절약
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
```
## 3단계 자동 최적화
### 1단계: FastPath — 패키지 함수 호출 (3~12x 빠름)
```prg
cResult := strings.ToUpper(cText)
```
gengo가 자동 생성:
```go
// 컴파일 시점에 타입 특화 함수 등록
var _ff_strings_ToUpper = hbrt.RegisterFastFunc("strings.ToUpper", strings.ToUpper)
// 런타임: reflect 우회, 타입 assertion 직접 호출
_results := hbrt.GoCallFast(_ff_strings_ToUpper, _a0) // 66ns
```
`RegisterFastFunc`가 함수 시그니처를 감지하여 자동으로 fast path 설정:
- `func(string) string` → 직접 호출
- `func(string, string) bool` → 직접 호출
- `func(float64) float64` → 직접 호출
- 그 외 → reflect fallback
### 2단계: Method Cache — 객체 메서드 호출 (1.8x 빠름)
```prg
db:Exec("CREATE TABLE ...")
```
gengo가 자동 생성:
```go
// 첫 호출: reflect.MethodByName → 캐시 저장
// 이후 호출: 캐시에서 즉시 조회
hbrt.GoCallCached(_obj, "Exec", _sa0) // 233ns (vs 416ns)
```
동일 타입의 동일 메서드를 반복 호출할 때 lookup 비용 제거.
### 3단계: 자동 타입 변환 — 메모리 3x 절약
| PRG 타입 | Go 타입 | 변환 비용 |
|----------|---------|-----------|
| String | string | zero-copy (포인터 전달) |
| Numeric(int) | int | 비트 캐스트 (0 alloc) |
| Numeric(double) | float64 | 비트 캐스트 (0 alloc) |
| Logical | bool | 비트 캐스트 (0 alloc) |
| Array | []T | 슬라이스 변환 (1 alloc) |
## 실전 성능 비교
### 10만 건 문자열 변환
```prg
FOR i := 1 TO 100000
aData[i] := strings.ToUpper(aData[i])
NEXT
```
| 방식 | 10만 건 | 100만 건 |
|------|---------|----------|
| Reflect (구버전) | 24ms | 243ms |
| **FastPath (현재)** | **6.6ms** | **66ms** |
| Native Go | 3.4ms | 34ms |
**PRG 코드가 native Go의 2배 이내 성능.**
### DB 대량 조회
```prg
aRows := SqlQuery(db, "SELECT * FROM products") // 10만 건
FOR i := 1 TO Len(aRows)
aRows[i]["name"] := strings.ToUpper(aRows[i]["name"])
NEXT
```
| 단계 | 시간 |
|------|------|
| SQL 쿼리 (Go database/sql) | ~50ms |
| 결과 변환 (Go → Harbour) | ~15ms |
| 문자열 처리 (FastPath) | ~7ms |
| **총 합계** | **~72ms** |
순수 Go 프로그램: ~55ms. **오버헤드 30% 미만.**
### HTTP 서버 요청 처리
```prg
// 요청마다 strings.Contains, fmt.Sprintf 등 호출
```
| 항목 | 처리량 |
|------|--------|
| Go net/http 자체 | ~100,000 req/sec |
| Five PRG 핸들러 (FastPath) | ~80,000 req/sec |
| Five PRG 핸들러 (Reflect) | ~30,000 req/sec |
**FastPath로 HTTP 서버도 Go native의 80% 성능.**
## 언제 차이가 나는가
### 차이 없음 (단일 호출)
```prg
db := sql.Open("sqlite", ":memory:") // 1회 호출 — 66ns vs 243ns = 무의미
cResult := strings.ToUpper("hello") // 1회 호출 — 체감 불가
```
### 차이 큼 (대량 반복)
```prg
FOR i := 1 TO 100000 // 10만 회 반복
aData[i] := strings.ToUpper(aData[i]) // FastPath: 6.6ms vs Reflect: 24ms
NEXT
DO WHILE rows:Next() // DB 전체 스캔
? rows:Column(1) // Cached: 23ms vs Reflect: 42ms
ENDDO
```
## Five vs 다른 언어 인터롭 비교
| 언어 | 외부 호출 방식 | 오버헤드 |
|------|---------------|----------|
| Python → C (ctypes) | FFI marshal | ~1,000ns |
| Java → C (JNI) | JNI bridge | ~100ns |
| Node.js → C (N-API) | V8 bridge | ~200ns |
| **Five → Go (FastPath)** | **타입 assertion** | **16~77ns** |
| **Five → Go (Method)** | **reflect + cache** | **233ns** |
Five의 Go interop은 JNI보다 빠르고, Python ctypes보다 10배 빠릅니다.
## 스트레스 테스트 결과
```
Volume: 40,000 calls (string/int/float/bool × 10,000) ✅
Large Data: 1MB string, 10,000 array, 1,000 map ✅
Boundary: int/int64/float64/string 극한값 ✅
Concurrent: 20,000 goroutine 동시 호출 ✅
Object: 1,000 객체 생성, method chain, nil safety ✅
Coercion: 7 × 6 = 42 타입 조합 중 41 성공 ✅
Fuzz: 5,000 랜덤 입력 검증 ✅
```
## 왜 빠른가 — 기술적 배경
1. **컴파일 타임 결정**: gengo가 IMPORT된 패키지를 분석하여 FastFunc 등록 코드 생성. 런타임 판단 비용 제로.
2. **타입 특화**: `func(string) string` 같은 common 시그니처는 `reflect.Call` 대신 Go 타입 assertion으로 직접 호출. alloc 7회 → 1회.
3. **메서드 캐시**: 동일 타입+메서드명의 `reflect.Method` lookup을 `sync.RWMutex` 보호 map에 캐시. 두 번째 호출부터 lookup 비용 제거.
4. **Zero-copy 문자열**: Harbour의 `HbString`과 Go의 `string`은 모두 불변(immutable). 포인터만 전달하면 복사 불필요.
5. **24바이트 Value**: Five의 Tagged Value는 24바이트 고정 크기. 스택 할당 가능, GC 압박 최소.