You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

异步多请求合并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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 04:10:30