382 lines
11 KiB
V
382 lines
11 KiB
V
import hono
|
|
import time
|
|
import net.http
|
|
import regex
|
|
|
|
// 模拟没有缓存的路由器(用于对比修复前的性能)
|
|
struct NoCacheRouter {
|
|
mut:
|
|
static_routes map[string]hono.IHandler
|
|
dynamic_routes []hono.IHandler
|
|
}
|
|
|
|
fn NoCacheRouter.new() NoCacheRouter {
|
|
return NoCacheRouter{
|
|
static_routes: map[string]hono.IHandler{}
|
|
dynamic_routes: []hono.IHandler{}
|
|
}
|
|
}
|
|
|
|
fn (mut router NoCacheRouter) add_route(method string, handler hono.IHandler, base_path string) {
|
|
full_path := handler.path
|
|
if !full_path.contains(':') && !full_path.contains('*') {
|
|
router.static_routes['${method}:${full_path}'] = handler
|
|
} else {
|
|
router.dynamic_routes << handler
|
|
}
|
|
}
|
|
|
|
// 每次都重新编译正则表达式(模拟修复前的行为)
|
|
fn (router NoCacheRouter) match_route_no_cache(method string, path string) ?hono.ContextRouteMatch {
|
|
// 静态路由匹配
|
|
key := '${method}:${path}'
|
|
if key in router.static_routes {
|
|
return hono.ContextRouteMatch{
|
|
handler: router.static_routes[key]
|
|
params: map[string]string{}
|
|
path: path
|
|
base_path: ''
|
|
}
|
|
}
|
|
|
|
// 动态路由匹配(每次重新编译正则表达式)
|
|
for handler in router.dynamic_routes {
|
|
if handler.path.contains(':') {
|
|
// 每次都重新编译正则表达式(这是性能瓶颈)
|
|
mut replaced_path := handler.path
|
|
mut param_names := []string{}
|
|
|
|
// 转义特殊字符
|
|
replaced_path = replaced_path.replace('?', r'\?')
|
|
replaced_path = replaced_path.replace('+', r'\+')
|
|
replaced_path = replaced_path.replace('.', r'\.')
|
|
replaced_path = replaced_path.replace('(', r'\(')
|
|
replaced_path = replaced_path.replace(')', r'\)')
|
|
replaced_path = replaced_path.replace('[', r'\[')
|
|
replaced_path = replaced_path.replace(']', r'\]')
|
|
replaced_path = replaced_path.replace('{', r'\{')
|
|
replaced_path = replaced_path.replace('}', r'\}')
|
|
replaced_path = replaced_path.replace('^', r'\^')
|
|
replaced_path = replaced_path.replace('$', r'\$')
|
|
replaced_path = replaced_path.replace('|', r'\|')
|
|
|
|
// 提取参数名并替换为命名捕获组
|
|
mut param_reg := regex.regex_opt(r':[a-zA-Z_][a-zA-Z0-9_]*') or { continue }
|
|
replaced_path = param_reg.replace_by_fn(replaced_path, fn [mut param_names] (re regex.RE, in_txt string, start int, end int) string {
|
|
param_name := in_txt[start+1..end]
|
|
param_names << param_name
|
|
return '(?P<${param_name}>[^/]+)'
|
|
})
|
|
|
|
replaced_path = '^${replaced_path}$'
|
|
|
|
// 每次都重新编译正则表达式(这是性能瓶颈)
|
|
mut reg := regex.regex_opt(replaced_path) or { continue }
|
|
|
|
if reg.matches_string(path) {
|
|
mut param_map := map[string]string{}
|
|
for param_name in param_names {
|
|
group := reg.get_group_by_name(path, param_name)
|
|
param_map[param_name] = group
|
|
}
|
|
|
|
return hono.ContextRouteMatch{
|
|
handler: handler
|
|
params: param_map
|
|
path: handler.path
|
|
base_path: ''
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return none
|
|
}
|
|
|
|
fn main() {
|
|
println('=== 路由性能百万级基准测试 (修复前 vs 修复后) ===')
|
|
|
|
// 测试1: 百万次路由匹配 - 小规模路由
|
|
test_million_matches_small_scale()
|
|
|
|
// 测试2: 百万次路由匹配 - 中等规模路由 (减少规模避免内存问题)
|
|
test_million_matches_medium_scale()
|
|
|
|
// 测试3: 百万次复杂路由匹配
|
|
test_million_complex_routes()
|
|
|
|
println('\n🎯 百万级基准测试完成')
|
|
}
|
|
|
|
fn test_million_matches_small_scale() {
|
|
println('\n📊 百万次路由匹配 - 小规模 (10个动态路由)...')
|
|
|
|
// 创建有缓存的路由器(修复后)
|
|
mut cached_router := hono.ContextHybridRouter.new()
|
|
|
|
// 创建无缓存的路由器(修复前)
|
|
mut no_cache_router := NoCacheRouter.new()
|
|
|
|
// 添加10个动态路由
|
|
dynamic_routes := [
|
|
'/users/:id',
|
|
'/posts/:post_id/comments/:comment_id',
|
|
'/api/v1/users/:user_id/posts/:post_id',
|
|
'/files/:category/:filename',
|
|
'/search/:query',
|
|
'/admin/users/:id/settings',
|
|
'/api/v2/projects/:project_id/tasks/:task_id',
|
|
'/shop/products/:id/reviews/:review_id',
|
|
'/blog/:year/:month/:slug',
|
|
'/docs/:section/:page'
|
|
]
|
|
|
|
for route in dynamic_routes {
|
|
handler := hono.ContextHandler{
|
|
path: route
|
|
handler: fn (mut c hono.Context) http.Response {
|
|
return c.text('test')
|
|
}
|
|
}
|
|
cached_router.add_route('GET', handler, '')
|
|
no_cache_router.add_route('GET', handler, '')
|
|
}
|
|
|
|
// 测试路径
|
|
test_paths := [
|
|
'/users/123',
|
|
'/posts/456/comments/789',
|
|
'/api/v1/users/101/posts/202',
|
|
'/files/images/photo.jpg',
|
|
'/search/test-query',
|
|
'/admin/users/555/settings',
|
|
'/api/v2/projects/777/tasks/888',
|
|
'/shop/products/999/reviews/111',
|
|
'/blog/2023/12/hello-world',
|
|
'/docs/api/authentication'
|
|
]
|
|
|
|
iterations := 100000 // 100万次 = 100000 * 10路径
|
|
|
|
println(' 准备进行 ${iterations * test_paths.len} 次路由匹配测试...')
|
|
|
|
// 测试修复后的路由器(有缓存)
|
|
println(' 🚀 测试修复后路由器 (有正则缓存)...')
|
|
start_time1 := time.now()
|
|
mut cached_matches := 0
|
|
for i in 0 .. iterations {
|
|
for path in test_paths {
|
|
if _ := cached_router.match_route('GET', path) {
|
|
cached_matches++
|
|
}
|
|
}
|
|
if i % 10000 == 0 {
|
|
print('.')
|
|
}
|
|
}
|
|
cached_time := time.since(start_time1)
|
|
println('')
|
|
|
|
// 测试修复前的路由器(无缓存)
|
|
println(' 🐌 测试修复前路由器 (无正则缓存)...')
|
|
start_time2 := time.now()
|
|
mut no_cache_matches := 0
|
|
for i in 0 .. iterations {
|
|
for path in test_paths {
|
|
if _ := no_cache_router.match_route_no_cache('GET', path) {
|
|
no_cache_matches++
|
|
}
|
|
}
|
|
if i % 10000 == 0 {
|
|
print('.')
|
|
}
|
|
}
|
|
no_cache_time := time.since(start_time2)
|
|
println('')
|
|
|
|
println(' 📊 小规模路由性能对比结果:')
|
|
println(' 修复后 (有缓存): ${cached_time} - 匹配成功: ${cached_matches}')
|
|
println(' 修复前 (无缓存): ${no_cache_time} - 匹配成功: ${no_cache_matches}')
|
|
|
|
if no_cache_time.milliseconds() > 0 && cached_time.milliseconds() > 0 {
|
|
improvement := f64(no_cache_time.milliseconds()) / f64(cached_time.milliseconds())
|
|
println(' 🎯 性能提升: ${improvement:.2f}x')
|
|
|
|
avg_cached := f64(cached_time.microseconds()) / f64(cached_matches)
|
|
avg_no_cache := f64(no_cache_time.microseconds()) / f64(no_cache_matches)
|
|
println(' 平均每次匹配 - 修复后: ${avg_cached:.2f}μs')
|
|
println(' 平均每次匹配 - 修复前: ${avg_no_cache:.2f}μs')
|
|
}
|
|
}
|
|
|
|
fn test_million_matches_medium_scale() {
|
|
println('\n📊 百万次路由匹配 - 中等规模 (20个动态路由)...')
|
|
|
|
mut cached_router := hono.ContextHybridRouter.new()
|
|
mut no_cache_router := NoCacheRouter.new()
|
|
|
|
// 添加20个动态路由(减少数量避免内存问题)
|
|
for i in 0 .. 20 {
|
|
route := '/api/v${i}/resources/:id/items/:item_id'
|
|
handler := hono.ContextHandler{
|
|
path: route
|
|
handler: fn (mut c hono.Context) http.Response {
|
|
return c.text('test')
|
|
}
|
|
}
|
|
cached_router.add_route('GET', handler, '')
|
|
no_cache_router.add_route('GET', handler, '')
|
|
}
|
|
|
|
// 测试路径(匹配不同的路由)
|
|
test_paths := [
|
|
'/api/v1/resources/123/items/456',
|
|
'/api/v5/resources/789/items/101',
|
|
'/api/v10/resources/111/items/222',
|
|
'/api/v15/resources/333/items/444',
|
|
'/api/v19/resources/555/items/666'
|
|
]
|
|
|
|
iterations := 200000 // 100万次 = 200000 * 5路径
|
|
|
|
println(' 准备进行 ${iterations * test_paths.len} 次路由匹配测试...')
|
|
|
|
// 测试修复后的路由器
|
|
println(' 🚀 测试修复后路由器...')
|
|
start_time1 := time.now()
|
|
mut cached_matches := 0
|
|
for i in 0 .. iterations {
|
|
for path in test_paths {
|
|
if _ := cached_router.match_route('GET', path) {
|
|
cached_matches++
|
|
}
|
|
}
|
|
if i % 20000 == 0 {
|
|
print('.')
|
|
}
|
|
}
|
|
cached_time := time.since(start_time1)
|
|
println('')
|
|
|
|
// 测试修复前的路由器(分批测试避免内存问题)
|
|
println(' 🐌 测试修复前路由器 (分批测试)...')
|
|
start_time2 := time.now()
|
|
mut no_cache_matches := 0
|
|
batch_size := 10000 // 分批处理
|
|
|
|
for batch in 0 .. (iterations / batch_size) {
|
|
for i in 0 .. batch_size {
|
|
for path in test_paths {
|
|
if _ := no_cache_router.match_route_no_cache('GET', path) {
|
|
no_cache_matches++
|
|
}
|
|
}
|
|
}
|
|
print('.')
|
|
}
|
|
no_cache_time := time.since(start_time2)
|
|
println('')
|
|
|
|
println(' 📊 中等规模路由性能对比结果:')
|
|
println(' 修复后 (有缓存): ${cached_time} - 匹配成功: ${cached_matches}')
|
|
println(' 修复前 (无缓存): ${no_cache_time} - 匹配成功: ${no_cache_matches}')
|
|
|
|
if no_cache_time.milliseconds() > 0 && cached_time.milliseconds() > 0 {
|
|
improvement := f64(no_cache_time.milliseconds()) / f64(cached_time.milliseconds())
|
|
println(' 🎯 性能提升: ${improvement:.2f}x')
|
|
}
|
|
}
|
|
|
|
fn test_million_complex_routes() {
|
|
println('\n📊 百万次复杂路由匹配测试...')
|
|
|
|
mut cached_router := hono.ContextHybridRouter.new()
|
|
mut no_cache_router := NoCacheRouter.new()
|
|
|
|
// 添加复杂的动态路由
|
|
complex_routes := [
|
|
'/api/:version/users/:user_id/posts/:post_id/comments/:comment_id',
|
|
'/shop/:category/:subcategory/products/:product_id/reviews/:review_id',
|
|
'/admin/:module/:action/:resource_type/:resource_id',
|
|
'/files/:year/:month/:day/:category/:filename',
|
|
'/docs/:language/:version/:section/:subsection/:page'
|
|
]
|
|
|
|
for route in complex_routes {
|
|
handler := hono.ContextHandler{
|
|
path: route
|
|
handler: fn (mut c hono.Context) http.Response {
|
|
return c.text('test')
|
|
}
|
|
}
|
|
cached_router.add_route('GET', handler, '')
|
|
no_cache_router.add_route('GET', handler, '')
|
|
}
|
|
|
|
// 复杂测试路径
|
|
test_paths := [
|
|
'/api/v1/users/123/posts/456/comments/789',
|
|
'/shop/electronics/phones/products/999/reviews/111',
|
|
'/admin/users/edit/profile/555',
|
|
'/files/2023/12/26/images/photo.jpg',
|
|
'/docs/en/v2/api/authentication/oauth'
|
|
]
|
|
|
|
iterations := 200000 // 100万次 = 200000 * 5路径
|
|
|
|
println(' 准备进行 ${iterations * test_paths.len} 次复杂路由匹配测试...')
|
|
|
|
// 测试修复后的路由器
|
|
println(' 🚀 测试修复后路由器...')
|
|
start_time1 := time.now()
|
|
mut cached_matches := 0
|
|
for i in 0 .. iterations {
|
|
for path in test_paths {
|
|
if _ := cached_router.match_route('GET', path) {
|
|
cached_matches++
|
|
}
|
|
}
|
|
if i % 20000 == 0 {
|
|
print('.')
|
|
}
|
|
}
|
|
cached_time := time.since(start_time1)
|
|
println('')
|
|
|
|
// 测试修复前的路由器(分批测试)
|
|
println(' 🐌 测试修复前路由器 (分批测试)...')
|
|
start_time2 := time.now()
|
|
mut no_cache_matches := 0
|
|
batch_size := 20000 // 分批处理
|
|
|
|
for batch in 0 .. (iterations / batch_size) {
|
|
for i in 0 .. batch_size {
|
|
for path in test_paths {
|
|
if _ := no_cache_router.match_route_no_cache('GET', path) {
|
|
no_cache_matches++
|
|
}
|
|
}
|
|
}
|
|
print('.')
|
|
}
|
|
no_cache_time := time.since(start_time2)
|
|
println('')
|
|
|
|
println(' 📊 复杂路由性能对比结果:')
|
|
println(' 修复后 (有缓存): ${cached_time} - 匹配成功: ${cached_matches}')
|
|
println(' 修复前 (无缓存): ${no_cache_time} - 匹配成功: ${no_cache_matches}')
|
|
|
|
if no_cache_time.milliseconds() > 0 && cached_time.milliseconds() > 0 {
|
|
improvement := f64(no_cache_time.milliseconds()) / f64(cached_time.milliseconds())
|
|
println(' 🎯 性能提升: ${improvement:.2f}x')
|
|
}
|
|
|
|
// 显示缓存统计
|
|
println('\n 📈 缓存统计信息:')
|
|
cache_size, cache_capacity := cached_router.get_cache_stats()
|
|
regex_total, regex_compiled := cached_router.get_regex_cache_stats()
|
|
|
|
println(' 路由缓存: ${cache_size}/${cache_capacity}')
|
|
println(' 正则缓存: ${regex_compiled}/${regex_total} 已编译')
|
|
|
|
cached_router.analyze_router_performance()
|
|
} |