异步多请求合并Future后await阻塞,进程挂起问题排查
问题根源
你代码卡住的核心原因是**AsyncHttpClient不支持同一个实例同时发起多个并发请求**。这个客户端内部基于单线程异步模型实现,一次只能处理一个请求的IO操作。你循环调用client.get(url)时,这些请求的Future其实在排队等待同一个客户端的处理资源,而all(futures)需要所有Future完成才能继续,后面的请求因前面的未处理完一直挂起,最终导致整个流程卡死。
解决方案
最简单的修复方式是为每个并发请求创建独立的AsyncHttpClient实例,让每个请求拥有自己的连接和IO处理通道,避免互相阻塞。
修改后的代码示例:
import benchy import std/[sugar, strformat, sequtils, httpclient, asyncfutures, asyncdispatch] proc callSite(url: static string, callCount: int): Future[string] {.async.} = var futures : seq[Future[AsyncResponse]] = @[] for x in 1..callCount: # 为每个请求创建独立的客户端 let client = newAsyncHttpClient() client.headers = newHttpHeaders({ "Authorization": "Bearer " & token, "Accept": "application/json" }) # 发起请求后,确保客户端在请求完成后关闭,避免资源泄漏 let reqFuture = client.get(url) proc cleanup() {.async.} = await reqFuture client.close() discard cleanup() futures.add reqFuture echo "pre combo" let responses = await all(futures) echo "post awaited combo" result = await responses[0].body echo "post response" const url = <Some URL> timeIt "campaign overview": let x = waitFor callSite(url, 3) keep(x)
额外说明
- 如果需要频繁发起并发请求,可自行实现简单的
AsyncHttpClient连接池,复用客户端实例以避免频繁创建销毁的开销,标准库未内置该功能,需自行封装。 - 务必在请求完成后关闭客户端,否则会造成TCP连接泄漏,耗尽系统资源。
内容的提问来源于stack exchange,提问作者Philipp Doerner
相关产品推荐
相关产品推荐

