Javascript Async setTimeout会阻止express处理,直到发生res.send

Javascript Async setTimeout会阻止express处理,直到发生res.send,javascript,node.js,express,Javascript,Node.js,Express,我有一个被委托给工作进程的异步操作 由于每个操作大约需要2秒钟,因此我希望在请求-响应中传递该操作的结果 我已将工作进程的执行包装在一个承诺中,在工作进程完成CPU密集型作业并返回结果之前,该承诺不会解决: module.exports = (req, res, controller) => { res.setHeader('Content-Type', 'application/json'); const workerService = controller.services.

我有一个被委托给工作进程的异步操作

由于每个操作大约需要2秒钟,因此我希望在请求-响应中传递该操作的结果

我已将工作进程的执行包装在一个承诺中,在工作进程完成CPU密集型作业并返回结果之前,该承诺不会解决:

module.exports = (req, res, controller) => {
  res.setHeader('Content-Type', 'application/json');

  const workerService = controller.services.workers;
  if (!workerService) {
    return res.json({
      ok: false,
      info: 'Worker service has not been started. Relaunch API server and check logs.'
    });
  }

  let commandObject = '';
  try {
    const postBody = req.body;
    // build a backtest execution command based on request params
    commandObject = getWorkerCommandFromPostBody(postBody);

  } catch (exception) {
    return res.json({
      ok: false,
      info: exception
    });
  }

  return controller.services.workers
    .promiseWorkerExecution(commandObject)
    .then(result => {
      if (result.context && result.context.results) {
        return res.end(result.context.results);
      }

      return res.end(result);
    })
    .catch(e => res.end(e));
}
这就是我困惑的地方。运行express进程的主线程没有被阻止。整个密集型操作被委托给一个专用的子流程(通过“集群”模块)

但是,如果我触发了其中3个请求,第二个请求甚至不会开始处理,直到第一个请求看到
res.end()
。这纯粹是在等待承诺的解决。我确信这可以通过承诺在几秒钟后等待setTimeout解决来重现

这是预期的吗?我想我可以把它当作异步操作,当我准备好了,这个请求-响应可以在承诺解决时发送

如果不在express服务器上运行集群,我是否无法继续接受对express服务器的并行请求?我希望有一台express服务器,并有独立的(受限制的)工作人员来委派/处理CPU密集型的工作

我需要跟踪并行运行的操作数量,所以我希望理想情况下不需要单独的express服务…有人对处理此问题有建议吗

编辑:我应该补充一点,我知道节点的单线程特性,但我认为只要它们不阻塞线程,就允许并行异步操作

编辑:我在沙箱中复制了该问题,仅使用setTimeout延迟res.send:

大家好,所以setTimeout是可复制的,这显然不是CPU密集型阻塞任务。沙箱:

通过在终端中触发此命令,我正在测试3个并行请求: 卷曲&卷曲&卷曲


沙盒服务器上的终端显示它正在阻止请求处理,直到当前请求发送响应,即使在异步回调中发生了问题,问题在于如何运行请求,而不是如何并行运行请求

curl https://nr41lkw95j.sse.codesandbox.io/test && curl https://nr41lkw95j.sse.codesandbox.io/test && curl https://nr41lkw95j.sse.codesandbox.io/test
当您使用
&&
时,它会等待上一个命令正确执行,而不会触发错误以执行下一个命令。如果要并行运行请求,必须执行以下操作:

curl https://nr41lkw95j.sse.codesandbox.io/test &
curl https://nr41lkw95j.sse.codesandbox.io/test &
curl https://nr41lkw95j.sse.codesandbox.io/test &
使用单个
&
,因此它在后台运行

另一种方法是使用ApacheBenchmark或类似程序

ab -n 9 -c 3 https://nr41lkw95j.sse.codesandbox.io/test
上述命令总共执行9个请求,并发度为3。 运行它,您将看到:

received request:  10
received request:  11
received request:  12
sent response:  10
sent response:  11
sent response:  12
received request:  13
received request:  14
received request:  15
sent response:  13
sent response:  14
sent response:  15
received request:  16
received request:  17
received request:  18
sent response:  16
sent response:  17
sent response:  18

这表明Node.js可以同时处理多个请求,除非阻止事件循环。

问题在于如何运行请求,而不是如何并行运行请求

curl https://nr41lkw95j.sse.codesandbox.io/test && curl https://nr41lkw95j.sse.codesandbox.io/test && curl https://nr41lkw95j.sse.codesandbox.io/test
当您使用
&&
时,它会等待上一个命令正确执行,而不会触发错误以执行下一个命令。如果要并行运行请求,必须执行以下操作:

curl https://nr41lkw95j.sse.codesandbox.io/test &
curl https://nr41lkw95j.sse.codesandbox.io/test &
curl https://nr41lkw95j.sse.codesandbox.io/test &
使用单个
&
,因此它在后台运行

另一种方法是使用ApacheBenchmark或类似程序

ab -n 9 -c 3 https://nr41lkw95j.sse.codesandbox.io/test
上述命令总共执行9个请求,并发度为3。 运行它,您将看到:

received request:  10
received request:  11
received request:  12
sent response:  10
sent response:  11
sent response:  12
received request:  13
received request:  14
received request:  15
sent response:  13
sent response:  14
sent response:  15
received request:  16
received request:  17
received request:  18
sent response:  16
sent response:  17
sent response:  18

这表明Node.js可以同时处理多个请求,除非您阻止事件循环。

注释不用于扩展讨论;此对话已完成。回答了您的问题,您使用了错误的命令进行测试。评论不用于扩展讨论;此对话已结束。回答了您的问题,您使用了错误的命令进行测试。不客气:)。这就是我昨天向您询问确切命令的原因,因为我认为您要么在限制并发请求的浏览器中运行该命令,要么您的命令不正确:)。但别担心,这就是我们从错误中学习的方式!。现在你知道Node.js可以毫无问题地处理并发性了。这就是我陷入这种困境的原因,我在Node中做并发性已经有一段时间了。只有express让我陷入了并发块的困境,对于我来说,它作为一个孤立点是没有意义的——特别是在没有线程阻塞的情况下。非常感谢你的帮助。当然是学习过程的一部分:)不客气:)。这就是我昨天向您询问确切命令的原因,因为我认为您要么在限制并发请求的浏览器中运行该命令,要么您的命令不正确:)。但别担心,这就是我们从错误中学习的方式!。现在你知道Node.js可以毫无问题地处理并发性了。这就是我陷入这种困境的原因,我在Node中做并发性已经有一段时间了。只有express让我陷入了并发块的困境,对于我来说,它作为一个孤立点是没有意义的——特别是在没有线程阻塞的情况下。非常感谢你的帮助。绝对是学习过程的一部分:)