如何在 Express 请求处理程序中编写非阻塞异步函数 [重复]

Posted

技术标签:

【中文标题】如何在 Express 请求处理程序中编写非阻塞异步函数 [重复]【英文标题】:How to write non-blocking async function in Express request handler [duplicate] 【发布时间】:2017-08-28 16:37:43 【问题描述】:

全部:

我是 Node 异步编程的新手,我想知道如何编写一些 Express 请求处理程序来处理耗时的繁重计算任务而不阻塞 Express 处理后续请求?

我认为 setTimeout 可以将作业置于事件循环中,但它仍然会阻止其他请求:

var express = require('express');
var router = express.Router();


function heavy(callback)
    setTimeout(callback, 1);


router.get('/', function(req, res, next) 
    var callback = function(req, res)
        var loop = +req.query.loop;
        for(var i=0; i<loop; i++)
            for(var j=0; j<loop; j++)
        
        res.send("finished task: "+Date.now());
    .bind(null, req, res);

    heavy(callback)
); 

我想我不明白 setTimeout 是如何工作的(我对 setTimeout 的理解是在 1 毫秒延迟之后,它将在单独的线程/进程中启动回调,而不会阻塞其他重调用),谁能告诉我该怎么做这不会阻止其他对heavy()的请求?

谢谢

【问题讨论】:

【参考方案1】:

最好使用 process.nextTick 或 setImmediate 代替 setTimeout(取决于您希望何时运行回调)。但是将长时间运行的代码放入函数中是不够的,因为它仍然会阻塞您的线程,只是一毫秒后。

您需要中断代码并多次运行 setImmediate 或 process.nextTick - 就像在每次迭代中一样,然后从中安排新的迭代。否则你将一无所获。

示例

而不是这样的代码:

var a = 0, b = 10000000;

function numbers() 
  while (a < b) 
    console.log("Number " + a++);
  


numbers();

你可以使用这样的代码:

var a = 0, b = 10000000;

function numbers() 
  var i = 0;
  while (a < b && i++ < 100) 
    console.log("Number " + a++);
  
  if (a < b) setImmediate(numbers);


numbers();

第一个会阻塞你的线程(并且可能会溢出你的调用堆栈),第二个不会阻塞(或者更准确地说,它会在很短的时间内阻塞你的线程 10000000 次,让其他东西运行在那些时刻之间)。

您还可以考虑生成一个外部进程或在 C/C++ 中编写一个本地插件,您可以在其中使用线程。

更多信息见:

How node.js server serve next request, if current request have huge computation? Maximum call stack size exceeded in nodejs Node; Q Promise delay How to avoid jimp blocking the code node.js NodeJS, Promises and performance

【讨论】:

谢谢,你能告诉我为什么在我的情况下,下一个请求仍然被阻止事件我使用 setTimeout?我认为 setTimeout 会选择一个不同的线程来运行该 heavy() 并让 Express 请求处理程序线程空闲。但似乎新的请求无法进来...... @Kuan setTimeout 在同一个线程中运行。它使代码稍后运行,但它仍然会在 setTimeout 回调运行时阻塞主线程和事件循环。您需要进行多个 setTimeouts(或 process.nextTick 或 setImmediate 回调),以使事件循环有机会在这些回调之间进行处理,正如我在回答中已经解释的那样。

以上是关于如何在 Express 请求处理程序中编写非阻塞异步函数 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

Linux 阻塞和非阻塞IO 实验

如何在 Undertow 的非阻塞处理程序中执行阻塞代码?

利用tornado使请求实现异步非阻塞

同步 异步 阻塞 非阻塞 的概念

如何在 express 中处理非 UTF-8 编码的 url

Java千百问_02基本使用(012)_如何编写非阻塞SocketChannel程序