Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d0298ea577 | ||
|
|
8e1007a1b4 | ||
|
|
6cdba50f36 |
@@ -342,8 +342,13 @@ pub fn (mut app Hono) listen(port string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 默认使用 picoev 高性能服务器
|
// 使用优化配置的 picoev 高性能服务器(支持高并发)
|
||||||
app.listen_picoev(port_num)
|
app.listen_picoev_with_config(PicoevConfig{
|
||||||
|
port: port_num
|
||||||
|
timeout_secs: 120 // 高并发场景需要更长超时
|
||||||
|
keepalive_timeout: 30 // Keep-Alive 超时 30 秒
|
||||||
|
max_keepalive_req: 10000 // 单连接最大请求数
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用传统 http.Server 启动(保留兼容性)
|
// 使用传统 http.Server 启动(保留兼容性)
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
# Quick concurrent test using runspaces
|
||||||
|
$url = "http://127.0.0.1:8888/"
|
||||||
|
$concurrency = 300
|
||||||
|
$requestsEach = 20
|
||||||
|
|
||||||
|
Write-Host "Testing $url with $concurrency concurrent workers, $requestsEach requests each"
|
||||||
|
Write-Host "Total: $($concurrency * $requestsEach) requests"
|
||||||
|
|
||||||
|
$runspacePool = [runspacefactory]::CreateRunspacePool(1, $concurrency)
|
||||||
|
$runspacePool.Open()
|
||||||
|
|
||||||
|
$scriptBlock = {
|
||||||
|
param($url, $count)
|
||||||
|
$s = 0; $f = 0
|
||||||
|
for ($i = 0; $i -lt $count; $i++) {
|
||||||
|
try {
|
||||||
|
$req = [System.Net.WebRequest]::Create($url)
|
||||||
|
$req.Timeout = 30000
|
||||||
|
$resp = $req.GetResponse()
|
||||||
|
if ($resp.StatusCode -eq "OK") { $s++ } else { $f++ }
|
||||||
|
$resp.Close()
|
||||||
|
} catch {
|
||||||
|
$f++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return @{Success=$s; Failed=$f}
|
||||||
|
}
|
||||||
|
|
||||||
|
$sw = [System.Diagnostics.Stopwatch]::StartNew()
|
||||||
|
$runspaces = @()
|
||||||
|
|
||||||
|
for ($i = 0; $i -lt $concurrency; $i++) {
|
||||||
|
$ps = [powershell]::Create()
|
||||||
|
$ps.RunspacePool = $runspacePool
|
||||||
|
$ps.AddScript($scriptBlock).AddArgument($url).AddArgument($requestsEach) | Out-Null
|
||||||
|
$runspaces += @{PS=$ps; Handle=$ps.BeginInvoke()}
|
||||||
|
}
|
||||||
|
|
||||||
|
$totalSuccess = 0
|
||||||
|
$totalFailed = 0
|
||||||
|
|
||||||
|
foreach ($rs in $runspaces) {
|
||||||
|
$result = $rs.PS.EndInvoke($rs.Handle)
|
||||||
|
$totalSuccess += $result.Success
|
||||||
|
$totalFailed += $result.Failed
|
||||||
|
$rs.PS.Dispose()
|
||||||
|
}
|
||||||
|
|
||||||
|
$sw.Stop()
|
||||||
|
$runspacePool.Close()
|
||||||
|
|
||||||
|
$total = $totalSuccess + $totalFailed
|
||||||
|
$rps = [math]::Round($total * 1000 / $sw.ElapsedMilliseconds, 2)
|
||||||
|
$rate = [math]::Round($totalSuccess * 100 / $total, 2)
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "Results:"
|
||||||
|
Write-Host " Total: $total"
|
||||||
|
Write-Host " Success: $totalSuccess"
|
||||||
|
Write-Host " Failed: $totalFailed"
|
||||||
|
Write-Host " Duration: $($sw.ElapsedMilliseconds) ms"
|
||||||
|
Write-Host " RPS: $rps"
|
||||||
|
Write-Host " Success Rate: $rate%"
|
||||||
|
|
||||||
|
if ($totalFailed -eq 0) {
|
||||||
|
Write-Host "PASSED - No connection errors!" -ForegroundColor Green
|
||||||
|
} else {
|
||||||
|
Write-Host "FAILED - $totalFailed errors occurred" -ForegroundColor Red
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
// 测试服务器 - 用于高并发测试
|
||||||
|
module main
|
||||||
|
|
||||||
|
import hono
|
||||||
|
import net.http
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
mut app := hono.Hono.new()
|
||||||
|
|
||||||
|
// 简单的测试路由
|
||||||
|
app.get('/', fn (mut c hono.Context) http.Response {
|
||||||
|
return c.text('OK')
|
||||||
|
})
|
||||||
|
|
||||||
|
app.get('/delay', fn (mut c hono.Context) http.Response {
|
||||||
|
// 模拟一些处理延迟
|
||||||
|
return c.text('OK with delay')
|
||||||
|
})
|
||||||
|
|
||||||
|
println('测试服务器启动中...')
|
||||||
|
println('配置: timeout_secs=120, keepalive_timeout=30, max_keepalive_req=10000')
|
||||||
|
|
||||||
|
app.listen(':8888')
|
||||||
|
}
|
||||||
+7
-9
@@ -11,12 +11,12 @@ pub:
|
|||||||
port int = 8080
|
port int = 8080
|
||||||
host string
|
host string
|
||||||
family net.AddrFamily = .ip6
|
family net.AddrFamily = .ip6
|
||||||
timeout_secs int = 8
|
timeout_secs int = 120 // 高并发场景需要更长超时(原 8 秒太短)
|
||||||
max_headers int = 100
|
max_headers int = 100
|
||||||
max_read int = 8192
|
max_read int = 8192
|
||||||
max_write int = 65536
|
max_write int = 65536
|
||||||
keepalive_timeout int = 5
|
keepalive_timeout int = 30 // Keep-Alive 超时延长到 30 秒
|
||||||
max_keepalive_req int = 1000
|
max_keepalive_req int = 10000 // 单连接最大请求数提升到 10000
|
||||||
}
|
}
|
||||||
|
|
||||||
// picoev 请求上下文
|
// picoev 请求上下文
|
||||||
@@ -229,14 +229,16 @@ fn send_picoev_response(mut res picohttpparser.Response, ctx Context, response h
|
|||||||
|
|
||||||
mut has_content_type := false
|
mut has_content_type := false
|
||||||
mut has_connection := false
|
mut has_connection := false
|
||||||
mut has_content_length := false
|
|
||||||
|
|
||||||
for key, value in ctx.headers {
|
for key, value in ctx.headers {
|
||||||
|
// 跳过 Content-Length,picohttpparser 会在 body() 时自动添加
|
||||||
|
if key.to_lower() == 'content-length' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
res.header(key, value)
|
res.header(key, value)
|
||||||
key_lower := key.to_lower()
|
key_lower := key.to_lower()
|
||||||
if key_lower == 'content-type' { has_content_type = true }
|
if key_lower == 'content-type' { has_content_type = true }
|
||||||
if key_lower == 'connection' { has_connection = true }
|
if key_lower == 'connection' { has_connection = true }
|
||||||
if key_lower == 'content-length' { has_content_length = true }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if content_type := response.header.get(.content_type) {
|
if content_type := response.header.get(.content_type) {
|
||||||
@@ -250,10 +252,6 @@ fn send_picoev_response(mut res picohttpparser.Response, ctx Context, response h
|
|||||||
res.header('Content-Type', 'text/plain; charset=utf-8')
|
res.header('Content-Type', 'text/plain; charset=utf-8')
|
||||||
}
|
}
|
||||||
|
|
||||||
if !has_content_length {
|
|
||||||
res.header('Content-Length', response.body.len.str())
|
|
||||||
}
|
|
||||||
|
|
||||||
if !has_connection {
|
if !has_connection {
|
||||||
if keepalive {
|
if keepalive {
|
||||||
res.header('Connection', 'keep-alive')
|
res.header('Connection', 'keep-alive')
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
Module {
|
Module {
|
||||||
name: 'hono'
|
name: 'hono'
|
||||||
description: 'A high-performance V language web framework inspired by Hono.js, featuring hybrid routing, LRU cache, middleware support, and more.'
|
description: 'A high-performance V language web framework inspired by Hono.js, featuring hybrid routing, LRU cache, middleware support, and more.'
|
||||||
version: '0.3.3'
|
version: '0.3.4'
|
||||||
license: 'MIT'
|
license: 'MIT'
|
||||||
dependencies: []
|
dependencies: []
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user