Nodejs express 怎么让线程不阻塞
Nodejs express 怎么让线程不阻塞
在 express 的路由那,
app.get(’/index’, function(req,res){res.send(‘aa’)}); app.get(’/list’, function(req,res){ var startTime = new Date().getTime(); while (new Date().getTime() < startTime + 10000); //实际上面这代码,是一段 cpu 密集型的操作,可能花几秒 res.send(‘bb’); });
当我先访问/ list ,再访问 /index,输出的aa 要等10秒 bb 输出后才输出。
express没有处理线程阻塞的东西么?如果这个要自己处理,那么代码应该怎么改呢?
Node.js Express 如何避免线程阻塞
在使用 Node.js 和 Express 构建 Web 应用时,经常会遇到一些长时间运行的任务,比如 CPU 密集型操作。这些任务可能会阻塞事件循环,导致其他请求无法及时处理。为了解决这个问题,我们可以使用异步编程技术来避免阻塞主线程。
示例代码
假设我们有以下两个路由:
const express = require('express');
const app = express();
// 模拟一个 CPU 密集型操作
function cpuIntensiveTask() {
return new Promise((resolve) => {
setTimeout(() => {
resolve("完成 CPU 密集型任务");
}, 10000); // 模拟耗时 10 秒的操作
});
}
app.get('/index', (req, res) => {
res.send('aa');
});
app.get('/list', async (req, res) => {
const startTime = new Date().getTime();
const result = await cpuIntensiveTask();
console.log(result);
res.send('bb');
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
解释
-
使用
async
和await
:- 我们将
/list
路由的处理函数定义为async
函数,这样就可以使用await
关键字来等待异步操作完成。
- 我们将
-
使用
Promise
和setTimeout
:cpuIntensiveTask
函数返回一个Promise
,并在Promise
中使用setTimeout
来模拟一个耗时 10 秒的操作。这样可以避免阻塞主线程,因为setTimeout
是非阻塞的。
-
异步处理:
- 当客户端请求
/list
时,Express 会立即返回Promise
并继续处理其他请求。一旦cpuIntensiveTask
完成,它会发送响应'bb'
。
- 当客户端请求
总结
通过使用 async
和 await
以及 Promise
,我们可以确保长时间运行的任务不会阻塞主线程。这样可以提高应用的响应性和整体性能。对于更复杂的任务,还可以考虑使用 Worker Threads 或第三方库如 node-cpu-worker
来进一步优化性能。
setTimeout可以吧。
有米有具体点的代码。。。。。。
node是单线程的,当遇到cpu密集操作的时候会造成下面的代码不会执行或者服务器假死的情况,你可以让c++封装那些cpu密集操作给js的api让开发者调用,或者用node提供的异步机制来处理 推荐用process.nextTick 在下一个事件循环中执行 process.nextTick( function () {
while (new Date().getTime() < startTime + 10000); } ) res.send(‘xxoo’);
一下这段话来自nodejs 官网,由坛子里大牛翻译的 0.10.X版本后用setImmediate 会好点
在0.8以及之前, process.nextTick() 会在当前事件循环结束时调用,这样通常是会在I/O开始前被调用的。所以很多项目都会使用process.nextTick()让它晚点做,而在I/O之前,看上去这样是正确的。事实上在大负载的I/O情况下,nextTick可能工作不正常,出现线程竞争情况。所以在v0.10.0版本 process.nextTick() 会在js代码执行完成后调用,而不是写入事件循环,可以说变同步了。应该尽量避免使用 process.nextTick() 来做递归,如果非要这么做请使用 setImmediate 来代替。
大概懂的了。。。
当在 Express 路由中执行 CPU 密集型操作时,这些操作会阻塞事件循环,导致其他请求需要等待。为了解决这个问题,你可以使用异步操作或利用工作线程(Worker Threads)来避免阻塞主线程。
示例代码
这里我们使用 setTimeout
来模拟异步操作,并使用 Promise 包装它:
const express = require('express');
const app = express();
function asyncOperation() {
return new Promise((resolve) => {
setTimeout(() => {
resolve('bb');
}, 10000); // 模拟耗时10秒的操作
});
}
app.get('/index', (req, res) => {
res.send('aa');
});
app.get('/list', async (req, res) => {
try {
const result = await asyncOperation();
res.send(result);
} catch (error) {
res.status(500).send('Internal Server Error');
}
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
解释
- 异步操作:通过将 CPU 密集型操作包装在一个
Promise
中,我们可以使用await
关键字来等待操作完成,而不会阻塞主线程。 - 路由处理:
/index
路由直接返回字符串 ‘aa’。/list
路由调用asyncOperation
函数,并使用await
等待结果。这使得asyncOperation
可以在后台运行,而不会阻塞主线程。
- 错误处理:使用
try...catch
结构来捕获可能的错误并返回适当的响应。
注意事项
- 如果 CPU 密集型操作非常复杂,可以考虑使用 Web Worker 或子进程(
child_process
)来进一步隔离计算任务。 - 使用
Promise
和async/await
可以简化异步代码的编写,同时保持代码的可读性和可维护性。
这样修改后,当你访问 /list
时,/index
不会被阻塞,两个请求可以并发处理。