Files
five/examples/go_concurrent.prg
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

148 lines
3.6 KiB
Plaintext

// Five Example: Concurrent Data Processing Pipeline
//
// Go goroutines + channels for parallel processing.
// 10만 건 레코드를 CPU 코어 수만큼 병렬 처리.
PROCEDURE Main()
LOCAL nRecords, aResult
nRecords := 100000
? "=== Five Concurrent Data Pipeline ==="
? "Processing", nRecords, "records with Go goroutines"
?
aResult := GoPipeline(nRecords)
? "Results:"
? " Total records:", aResult["total"]
? " Total amount: ", aResult["amount"]
? " Avg per record:", aResult["average"]
? " Max single: ", aResult["max"]
? " Min single: ", aResult["min"]
? " Processing ms:", aResult["elapsed_ms"]
? " Records/sec: ", aResult["throughput"]
?
? "Category breakdown:"
? " Electronics: ", aResult["cat_electronics"]
? " Clothing: ", aResult["cat_clothing"]
? " Food: ", aResult["cat_food"]
? " Books: ", aResult["cat_books"]
RETURN
#pragma BEGINDUMP
import (
"five/hbrt"
"fmt"
"math"
"math/rand"
"runtime"
"strings"
"sync"
"time"
)
func init() {
hbrt.HB_FUNC("GOPIPELINE", goPipeline)
}
type record struct {
id int
category string
amount float64
quantity int
}
type summary struct {
total int
amount float64
max, min float64
categories map[string]float64
}
func goPipeline(ctx *hbrt.HBContext) {
nRecords := ctx.ParNIDef(1, 100000)
numWorkers := runtime.NumCPU()
start := time.Now()
// Stage 1: Generate records (simulates DB read)
recordCh := make(chan record, 1000)
go func() {
categories := []string{"Electronics", "Clothing", "Food", "Books"}
for i := 0; i < nRecords; i++ {
recordCh <- record{
id: i + 1,
category: categories[rand.Intn(len(categories))],
amount: math.Round(rand.Float64()*1000*100) / 100,
quantity: rand.Intn(50) + 1,
}
}
close(recordCh)
}()
// Stage 2: Transform (parallel workers)
type transformed struct {
category string
total float64
}
transformCh := make(chan transformed, 1000)
var wg sync.WaitGroup
for w := 0; w < numWorkers; w++ {
wg.Add(1)
go func() {
defer wg.Done()
for r := range recordCh {
total := r.amount * float64(r.quantity)
total = math.Round(total*100) / 100
transformCh <- transformed{category: r.category, total: total}
}
}()
}
go func() {
wg.Wait()
close(transformCh)
}()
// Stage 3: Aggregate
sum := summary{
min: math.MaxFloat64,
categories: make(map[string]float64),
}
for t := range transformCh {
sum.total++
sum.amount += t.total
if t.total > sum.max {
sum.max = t.total
}
if t.total < sum.min {
sum.min = t.total
}
sum.categories[t.category] += t.total
}
elapsed := time.Since(start)
// Build result hash for PRG
result := ctx.HashNew()
ctx.HashAdd(result, hbrt.MakeString("total"), hbrt.MakeInt(sum.total))
ctx.HashAdd(result, hbrt.MakeString("amount"), hbrt.MakeDouble(sum.amount, 0, 0))
ctx.HashAdd(result, hbrt.MakeString("average"), hbrt.MakeDouble(sum.amount/float64(sum.total), 0, 0))
ctx.HashAdd(result, hbrt.MakeString("max"), hbrt.MakeDouble(sum.max, 0, 0))
ctx.HashAdd(result, hbrt.MakeString("min"), hbrt.MakeDouble(sum.min, 0, 0))
ctx.HashAdd(result, hbrt.MakeString("elapsed_ms"), hbrt.MakeInt(int(elapsed.Milliseconds())))
throughput := fmt.Sprintf("%.0f", float64(nRecords)/elapsed.Seconds())
ctx.HashAdd(result, hbrt.MakeString("throughput"), hbrt.MakeString(throughput))
for _, cat := range []string{"Electronics", "Clothing", "Food", "Books"} {
key := "cat_" + strings.ToLower(cat)
ctx.HashAdd(result, hbrt.MakeString(key), hbrt.MakeDouble(sum.categories[cat], 0, 0))
}
ctx.RetVal(result)
}
#pragma ENDDUMP