Files
v-hono/tests/benchmark_vweb_vs_hono.v
meiseayoung 3b8d21dd0d fix: update import path to VPM package name (meiseayoung.hono)
- Change all `import hono` to `import meiseayoung.hono` in code and docs
- Ensure compatibility with VPM installation via `v install meiseayoung.hono`
2026-01-02 22:05:12 +08:00

292 lines
9.2 KiB
V

// vweb vs v-hono 性能对比测试
// 测试路由匹配性能(不启动实际服务器)
module main
import time
import meiseayoung.hono
import net.http
// ============================================
// 测试配置
// ============================================
const iterations = 100_000
const warmup_iterations = 1000
// ============================================
// v-hono 路由测试
// ============================================
fn setup_hono_app() hono.Hono {
mut app := hono.Hono.new()
// 静态路由
app.get('/', fn (mut c hono.Context) http.Response {
return c.text('Hello World')
})
app.get('/api/health', fn (mut c hono.Context) http.Response {
return c.text('OK')
})
app.get('/api/users', fn (mut c hono.Context) http.Response {
return c.json('{"users": []}')
})
app.post('/api/users', fn (mut c hono.Context) http.Response {
return c.json('{"created": true}')
})
// 动态路由
app.get('/api/users/:id', fn (mut c hono.Context) http.Response {
id := c.params['id'] or { '' }
return c.json('{"id": "${id}"}')
})
app.get('/api/users/:id/posts', fn (mut c hono.Context) http.Response {
return c.json('{"posts": []}')
})
app.get('/api/users/:id/posts/:post_id', fn (mut c hono.Context) http.Response {
return c.json('{"post": {}}')
})
app.get('/api/categories/:cat/items/:item', fn (mut c hono.Context) http.Response {
return c.json('{"item": {}}')
})
return app
}
fn benchmark_hono_routing(mut app hono.Hono) {
println('\n========================================')
println('v-hono 路由性能测试')
println('========================================')
// 测试路径
test_paths := [
['GET', '/'],
['GET', '/api/health'],
['GET', '/api/users'],
['POST', '/api/users'],
['GET', '/api/users/123'],
['GET', '/api/users/456/posts'],
['GET', '/api/users/789/posts/101'],
['GET', '/api/categories/electronics/items/phone'],
]
// 预热
println('预热中 (${warmup_iterations} 次)...')
for _ in 0 .. warmup_iterations {
for path_info in test_paths {
method := path_info[0]
path := path_info[1]
app.fast_router.match_route(method, path) or { continue }
}
}
// 正式测试
println('正式测试 (${iterations} 次)...\n')
mut total_time := i64(0)
mut match_count := 0
for path_info in test_paths {
method := path_info[0]
path := path_info[1]
sw := time.new_stopwatch()
for _ in 0 .. iterations {
if _ := app.fast_router.match_route(method, path) {
match_count++
}
}
elapsed := sw.elapsed()
total_time += elapsed.nanoseconds()
avg_ns := elapsed.nanoseconds() / iterations
ops_per_sec := if avg_ns > 0 { 1_000_000_000 / avg_ns } else { 0 }
println(' ${method} ${path}')
println(' 总耗时: ${elapsed}')
println(' 平均: ${avg_ns} ns/op')
println(' 吞吐: ${ops_per_sec} ops/sec')
println('')
}
total_ops := iterations * test_paths.len
avg_total_ns := total_time / total_ops
total_ops_per_sec := if avg_total_ns > 0 { 1_000_000_000 / avg_total_ns } else { 0 }
println('----------------------------------------')
println('v-hono 总计:')
println(' 总操作数: ${total_ops}')
println(' 总耗时: ${total_time / 1_000_000} ms')
println(' 平均: ${avg_total_ns} ns/op')
println(' 吞吐: ${total_ops_per_sec} ops/sec')
}
// ============================================
// 简单的路由匹配模拟(模拟 vweb 的路由行为)
// ============================================
struct SimpleRouter {
mut:
routes map[string]string
}
fn SimpleRouter.new() SimpleRouter {
return SimpleRouter{
routes: map[string]string{}
}
}
fn (mut r SimpleRouter) add(method string, path string) {
r.routes['${method}:${path}'] = path
}
fn (r SimpleRouter) match_static(method string, path string) ?string {
key := '${method}:${path}'
if key in r.routes {
return r.routes[key]
}
return none
}
// 模拟 vweb 的简单路由匹配(基于字符串比较)
fn (r SimpleRouter) match_simple(method string, path string) ?string {
// vweb 使用属性注解和函数名映射,这里模拟其基本行为
key := '${method}:${path}'
if key in r.routes {
return r.routes[key]
}
// 简单的动态路由匹配(模拟 vweb 的参数提取)
for route_key, route_path in r.routes {
if route_key.starts_with('${method}:') {
if match_dynamic_simple(route_path, path) {
return route_path
}
}
}
return none
}
// 简单的动态路由匹配
fn match_dynamic_simple(pattern string, path string) bool {
pattern_parts := pattern.split('/')
path_parts := path.split('/')
if pattern_parts.len != path_parts.len {
return false
}
for i, part in pattern_parts {
if part.starts_with(':') {
continue // 参数匹配任意值
}
if part != path_parts[i] {
return false
}
}
return true
}
fn benchmark_simple_routing() {
println('\n========================================')
println('简单路由器性能测试 (模拟 vweb 行为)')
println('========================================')
mut router := SimpleRouter.new()
// 添加路由
router.add('GET', '/')
router.add('GET', '/api/health')
router.add('GET', '/api/users')
router.add('POST', '/api/users')
router.add('GET', '/api/users/:id')
router.add('GET', '/api/users/:id/posts')
router.add('GET', '/api/users/:id/posts/:post_id')
router.add('GET', '/api/categories/:cat/items/:item')
test_paths := [
['GET', '/'],
['GET', '/api/health'],
['GET', '/api/users'],
['POST', '/api/users'],
['GET', '/api/users/123'],
['GET', '/api/users/456/posts'],
['GET', '/api/users/789/posts/101'],
['GET', '/api/categories/electronics/items/phone'],
]
// 预热
println('预热中 (${warmup_iterations} 次)...')
for _ in 0 .. warmup_iterations {
for path_info in test_paths {
method := path_info[0]
path := path_info[1]
router.match_simple(method, path) or { continue }
}
}
// 正式测试
println('正式测试 (${iterations} 次)...\n')
mut total_time := i64(0)
for path_info in test_paths {
method := path_info[0]
path := path_info[1]
sw := time.new_stopwatch()
for _ in 0 .. iterations {
router.match_simple(method, path) or { continue }
}
elapsed := sw.elapsed()
total_time += elapsed.nanoseconds()
avg_ns := elapsed.nanoseconds() / iterations
ops_per_sec := if avg_ns > 0 { 1_000_000_000 / avg_ns } else { 0 }
println(' ${method} ${path}')
println(' 总耗时: ${elapsed}')
println(' 平均: ${avg_ns} ns/op')
println(' 吞吐: ${ops_per_sec} ops/sec')
println('')
}
total_ops := iterations * test_paths.len
avg_total_ns := total_time / total_ops
total_ops_per_sec := if avg_total_ns > 0 { 1_000_000_000 / avg_total_ns } else { 0 }
println('----------------------------------------')
println('简单路由器 总计:')
println(' 总操作数: ${total_ops}')
println(' 总耗时: ${total_time / 1_000_000} ms')
println(' 平均: ${avg_total_ns} ns/op')
println(' 吞吐: ${total_ops_per_sec} ops/sec')
}
// ============================================
// 主函数
// ============================================
fn main() {
println('╔══════════════════════════════════════════════════════════════╗')
println('║ vweb vs v-hono 路由性能对比测试 ║')
println('╠══════════════════════════════════════════════════════════════╣')
println('║ 测试内容: 路由匹配性能 ║')
println('║ 迭代次数: ${iterations} ║')
println('║ 预热次数: ${warmup_iterations} ║')
println('╚══════════════════════════════════════════════════════════════╝')
// 测试简单路由器(模拟 vweb)
benchmark_simple_routing()
// 测试 v-hono
mut hono_app := setup_hono_app()
benchmark_hono_routing(mut hono_app)
// 输出对比总结
println('\n╔══════════════════════════════════════════════════════════════╗')
println('║ 测试完成 ║')
println('╠══════════════════════════════════════════════════════════════╣')
println('║ 说明: ║')
println('║ - 简单路由器模拟了 vweb 的基本路由匹配行为 ║')
println('║ - v-hono 使用了优化的 FastRouter 和缓存机制 ║')
println('║ - 实际 HTTP 服务器性能还受网络 I/O 等因素影响 ║')
println('╚══════════════════════════════════════════════════════════════╝')
}