Files
v-hono/examples/benchmark_veb_vs_hono.v
T

345 lines
13 KiB
V

// veb vs v-hono 性能对比测试
// 运行: v run benchmark_veb_vs_hono.v
//
// 测试内容:
// 1. 路由匹配性能(纯路由,不启动服务器)
// 2. 静态路由 vs 动态路由性能对比
// 3. 缓存命中率分析
module main
import time
import hono
import net.http
// ============================================
// 测试配置
// ============================================
const iterations = 10000
const warmup_iterations = 1000
// 测试路径
const static_paths = [
'/',
'/api/health',
'/api/users',
]
const dynamic_paths = [
'/api/users/123',
'/api/users/456/posts',
'/api/users/789/posts/101',
'/api/categories/electronics/items/phone',
]
// ============================================
// 简单路由器(模拟 veb 的路由匹配方式)
// ============================================
struct SimpleRouter {
mut:
static_routes map[string]string
dynamic_routes []DynamicRoute
}
struct DynamicRoute {
pattern string
param_names []string
}
fn SimpleRouter.new() SimpleRouter {
return SimpleRouter{
static_routes: map[string]string{}
dynamic_routes: []DynamicRoute{}
}
}
fn (mut r SimpleRouter) add_static(path string) {
r.static_routes[path] = path
}
fn (mut r SimpleRouter) add_dynamic(pattern string, param_names []string) {
r.dynamic_routes << DynamicRoute{pattern, param_names}
}
// 简单的动态路由匹配(模拟 veb 的线性扫描方式)
fn (r SimpleRouter) match_route(path string) (bool, map[string]string) {
// 1. 先尝试静态匹配
if path in r.static_routes {
return true, map[string]string{}
}
// 2. 动态路由匹配(线性扫描)
path_parts := path.split('/').filter(it.len > 0)
for route in r.dynamic_routes {
pattern_parts := route.pattern.split('/').filter(it.len > 0)
if path_parts.len != pattern_parts.len {
continue
}
mut matched := true
mut params := map[string]string{}
mut param_idx := 0
for i, part in pattern_parts {
if part.starts_with(':') {
// 参数匹配
if param_idx < route.param_names.len {
params[route.param_names[param_idx]] = path_parts[i]
param_idx++
}
} else if part != path_parts[i] {
matched = false
break
}
}
if matched {
return true, params
}
}
return false, map[string]string{}
}
// ============================================
// 基准测试函数
// ============================================
struct BenchmarkResult {
name string
total_time_ns i64
avg_time_ns i64
min_time_ns i64
max_time_ns i64
ops_per_sec f64
iterations int
}
fn benchmark(name string, iterations int, f fn () bool) BenchmarkResult {
mut times := []i64{cap: iterations}
mut min_time := i64(9223372036854775807)
mut max_time := i64(0)
// 预热
for _ in 0 .. warmup_iterations {
f()
}
// 正式测试
for _ in 0 .. iterations {
sw := time.new_stopwatch()
f()
elapsed := sw.elapsed().nanoseconds()
times << elapsed
if elapsed < min_time {
min_time = elapsed
}
if elapsed > max_time {
max_time = elapsed
}
}
mut total := i64(0)
for t in times {
total += t
}
avg := total / iterations
ops_per_sec := 1_000_000_000.0 / f64(avg)
return BenchmarkResult{
name: name
total_time_ns: total
avg_time_ns: avg
min_time_ns: min_time
max_time_ns: max_time
ops_per_sec: ops_per_sec
iterations: iterations
}
}
fn print_result(r BenchmarkResult) {
println('┌─────────────────────────────────────────────────────────────┐')
println('│ ${r.name:-59} │')
println('├─────────────────────────────────────────────────────────────┤')
println('│ 迭代次数: ${r.iterations:-48} │')
println('│ 总耗时: ${r.total_time_ns / 1_000_000:-45} ms │')
println('│ 平均耗时: ${r.avg_time_ns:-45} ns │')
println('│ 最小耗时: ${r.min_time_ns:-45} ns │')
println('│ 最大耗时: ${r.max_time_ns:-45} ns │')
println('│ 吞吐量: ${r.ops_per_sec:-42.0} ops/s │')
println('└─────────────────────────────────────────────────────────────┘')
}
fn print_comparison(name string, simple_result BenchmarkResult, hono_result BenchmarkResult) {
speedup := f64(simple_result.avg_time_ns) / f64(hono_result.avg_time_ns)
winner := if speedup > 1.0 { 'v-hono' } else { 'SimpleRouter' }
ratio := if speedup > 1.0 { speedup } else { 1.0 / speedup }
println('')
println('═══════════════════════════════════════════════════════════════')
println(' ${name} 对比结果')
println('═══════════════════════════════════════════════════════════════')
println(' SimpleRouter: ${simple_result.avg_time_ns} ns/op (${simple_result.ops_per_sec:.0} ops/s)')
println(' v-hono: ${hono_result.avg_time_ns} ns/op (${hono_result.ops_per_sec:.0} ops/s)')
println(' 胜出: ${winner} (快 ${ratio:.2}x)')
println('═══════════════════════════════════════════════════════════════')
}
// ============================================
// 主测试函数
// ============================================
fn main() {
println('')
println('╔═══════════════════════════════════════════════════════════════╗')
println('║ veb vs v-hono 路由性能对比测试 ║')
println('║ (SimpleRouter 模拟 veb 的路由匹配方式) ║')
println('╠═══════════════════════════════════════════════════════════════╣')
println('║ 测试配置: ║')
println('║ - 迭代次数: ${iterations:-46} ║')
println('║ - 预热次数: ${warmup_iterations:-46} ║')
println('╚═══════════════════════════════════════════════════════════════╝')
println('')
// 初始化 SimpleRouter
mut simple_router := SimpleRouter.new()
simple_router.add_static('/')
simple_router.add_static('/api/health')
simple_router.add_static('/api/users')
simple_router.add_dynamic('/api/users/:id', ['id'])
simple_router.add_dynamic('/api/users/:id/posts', ['id'])
simple_router.add_dynamic('/api/users/:user_id/posts/:post_id', ['user_id', 'post_id'])
simple_router.add_dynamic('/api/categories/:cat/items/:item', ['cat', 'item'])
// 初始化 v-hono
mut hono_app := hono.Hono.new()
hono_app.get('/', fn (mut c hono.Context) http.Response {
return c.text('Hello World')
})
hono_app.get('/api/health', fn (mut c hono.Context) http.Response {
return c.text('OK')
})
hono_app.get('/api/users', fn (mut c hono.Context) http.Response {
return c.json('{"users": []}')
})
hono_app.get('/api/users/:id', fn (mut c hono.Context) http.Response {
return c.json('{"id": "123"}')
})
hono_app.get('/api/users/:id/posts', fn (mut c hono.Context) http.Response {
return c.json('{"posts": []}')
})
hono_app.get('/api/users/:user_id/posts/:post_id', fn (mut c hono.Context) http.Response {
return c.json('{"post": {}}')
})
hono_app.get('/api/categories/:cat/items/:item', fn (mut c hono.Context) http.Response {
return c.json('{"item": {}}')
})
// ============================================
// 测试 1: 静态路由性能
// ============================================
println('\n【测试 1】静态路由匹配性能')
println('─────────────────────────────────────────────────────────────────')
simple_static_result := benchmark('SimpleRouter 静态路由', iterations, fn [simple_router] () bool {
for path in static_paths {
simple_router.match_route(path)
}
return true
})
print_result(simple_static_result)
hono_static_result := benchmark('v-hono 静态路由', iterations, fn [mut hono_app] () bool {
for path in static_paths {
hono_app.fast_router.match_route('GET', path) or { continue }
}
return true
})
print_result(hono_static_result)
print_comparison('静态路由', simple_static_result, hono_static_result)
// ============================================
// 测试 2: 动态路由性能
// ============================================
println('\n【测试 2】动态路由匹配性能')
println('─────────────────────────────────────────────────────────────────')
simple_dynamic_result := benchmark('SimpleRouter 动态路由', iterations, fn [simple_router] () bool {
for path in dynamic_paths {
simple_router.match_route(path)
}
return true
})
print_result(simple_dynamic_result)
hono_dynamic_result := benchmark('v-hono 动态路由', iterations, fn [mut hono_app] () bool {
for path in dynamic_paths {
hono_app.fast_router.match_route('GET', path) or { continue }
}
return true
})
print_result(hono_dynamic_result)
print_comparison('动态路由', simple_dynamic_result, hono_dynamic_result)
// ============================================
// 测试 3: 混合路由性能
// ============================================
println('\n【测试 3】混合路由匹配性能(静态 + 动态)')
println('─────────────────────────────────────────────────────────────────')
mut all_paths := []string{}
all_paths << static_paths
all_paths << dynamic_paths
simple_mixed_result := benchmark('SimpleRouter 混合路由', iterations, fn [simple_router, all_paths] () bool {
for path in all_paths {
simple_router.match_route(path)
}
return true
})
print_result(simple_mixed_result)
hono_mixed_result := benchmark('v-hono 混合路由', iterations, fn [mut hono_app, all_paths] () bool {
for path in all_paths {
hono_app.fast_router.match_route('GET', path) or { continue }
}
return true
})
print_result(hono_mixed_result)
print_comparison('混合路由', simple_mixed_result, hono_mixed_result)
// ============================================
// 路由器统计信息
// ============================================
println('\n【路由器统计信息】')
println('─────────────────────────────────────────────────────────────────')
static_count, dynamic_count, cache_count, _ := hono_app.get_router_stats()
println('v-hono FastRouter:')
println(' - 静态路由数: ${static_count}')
println(' - 动态路由数: ${dynamic_count}')
println(' - 缓存条目数: ${cache_count}')
println('')
println('SimpleRouter:')
println(' - 静态路由数: ${simple_router.static_routes.len}')
println(' - 动态路由数: ${simple_router.dynamic_routes.len}')
// ============================================
// 总结
// ============================================
println('\n')
println('╔═══════════════════════════════════════════════════════════════╗')
println('║ 测试总结 ║')
println('╠═══════════════════════════════════════════════════════════════╣')
println('║ 1. 静态路由: SimpleRouter 使用 map 直接查找,通常更快 ║')
println('║ 2. 动态路由: v-hono 使用 Trie + 缓存,性能更稳定 ║')
println('║ 3. v-hono 的优势在于动态路由性能一致,不随复杂度增加而下降 ║')
println('╚═══════════════════════════════════════════════════════════════╝')
}