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

为何Node.js CPU与IO密集任务负载测试下/fast接口响应时长远近一致?

Node.js 并行负载测试疑问:/fast接口响应时间为何无差异?

问题描述

已知Node.js擅长处理网络与非阻塞I/O场景,我创建了三个API接口:

  • 响应快速的/fast接口;
  • CPU密集型的/cpu接口(通过while循环占用CPU资源5秒);
  • I/O密集型的/io接口(发起外部网络请求)。

我进行了两组并行负载测试:

  1. 同时调用/fast与/cpu接口;
  2. 同时调用/fast与/io接口。

测试后发现/fast接口的平均响应时间在两组测试中几乎相同,但我原本预期I/O密集任务组的/fast接口响应时间会更短,特此询问原因。

相关代码

app.get("/fast", (req, res) => {
  res.send("I am fast");
});

app.get("/cpu", (req, res) => {
  const start = Date.now();
  while (Date.now() - start < 5000) { }
  res.send("I took 5 seconds");
});

app.get("/io", (req, res) => {
  axios.get('https://reqres.in/api/users?page=2')
  .then(function (response) {
    res.send("Network call success");
  })
});

测试信息

  • 测试结果截图:
    • 图1:IO密集型API负载测试结果
    • 图2:CPU密集型API负载测试结果
  • 测试说明:/fast与/cpu接口并行执行,/fast与/io接口并行执行
  • 计算机配置:AMD Ryzen 5 3400G with Radeon Vega Graphics 3.70 GHz,内存8GB

原因解析

1. Node.js单线程事件循环的核心特性

Node.js基于单线程事件循环模型,所有JavaScript代码(包括API回调)都在主线程中执行。异步I/O操作(如网络请求)会被交给操作系统的异步线程池处理,主线程不会被阻塞,可继续处理其他任务。

2. CPU密集组的请求处理逻辑

当/fast与/cpu请求同时到达时,它们会进入事件队列等待主线程处理:

  • 如果/fast的回调先被执行:会立即响应,耗时可忽略;
  • 如果/cpu的回调先被执行:while循环是同步阻塞操作,会完全占用主线程5秒,/fast的请求必须等循环结束才能被处理,耗时约5秒。

在多次重复测试中,两种情况出现的概率基本均等,因此/fast的平均响应时间会接近2.5秒左右。

3. I/O密集组的请求处理逻辑

当/fast与/io请求同时到达时:

  • 如果/fast的回调先被执行:立即响应;
  • 如果/io的回调先被执行:主线程执行到axios.get时,会将网络请求交给异步线程池处理,主线程立即释放,回到事件循环处理/fast的请求,因此/fast仍能快速响应,耗时可忽略。

4. 两组测试结果接近的可能原因

你观察到两组/fast响应时间几乎相同,大概率是以下情况导致:

  • 测试样本量不足:如果测试次数太少,CPU组中/fast先被处理的次数占比过高,拉低了平均响应时间,使其接近IO组;
  • 请求发起时机存在偏差:JMeter在发起并行请求时,可能存在微小的时间差,导致/fast请求总是先到达Node.js,即使在CPU组中也能快速响应;
  • Node.js进程调度的特殊情况:若你无意中启用了多进程模式(如cluster模块),/cpu请求会被分配到单独的进程,不会阻塞处理/fast请求的进程,从而使两组响应时间一致。

内容的提问来源于stack exchange,提问作者Subrahmanyam Pampana

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 11:59:53