每当我在位置B运行我的'save_to_db'函数时,它就会失败。
下面的代码显示了问题...
//location A
var i = 0;
while(true)
{
i++;
if(i == 100)
{
//location B
save_to_db(newUnit, 11214.1, 'TEST');
}
}
//location C
函数“ save_to_db”在位置A和C处正常工作,但在位置B处失败。
我认为这是因为while循环是无限且同步的。因此,它不会给nodejs运行事件循环的机会。在这种情况下,如何给nodejs一个运行其事件循环的机会?
=====================更新========================= ======
上面的代码是该代码的非常简化的版本。我有一个名为“ db_util”的类/模块,它有两个方法,“ save_to_db”和“ read_from_db”。我认为由于这些方法使用了“ mysql”模块,因此它们以异步方式访问数据库。但是我的while true循环阻止了nodejs eventloop。因此,while循环中的任何方法都没有机会被调用。
var mysql = require('mysql');
var db_util = function()
{}
db_util.prototype = {
save_to_db: function (neural_network, fitness, type) {
var connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: '',
database: 'nodejstestdb'
});
connection.connect();
var addSql = 'INSERT INTO mytable(id, nn, type, fitness) VALUES(?,?,?,?)';
var addSqlParams = [null, neural_network, type, fitness];
connection.query(addSql, addSqlParams, function (err, result) {
if (err) {
console.log('[INSERT ERROR] - ', err.message);
return;
}
console.log('INSERT ID:', result);
});
connection.end();
},
read_from_db:function(){
var connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: '',
database: 'nodejstestdb'
});
connection.connect();
var sql = 'SELECT * FROM mytable ORDER BY fitness DESC';
connection.query(sql, function (err, result) {
if (err) {
console.log('[SELECT ERROR] - ', err.message);
return;
}
console.log(result);
var nn = result[0].nn;
neural_network = synaptic.Network.fromJSON(JSON.parse(nn));
return neural_network;
});
connection.end();
}
}
module.exports = db_util;
=================由于答案而更新2
let i = 0;
(function tick() {
++i;
if (i%100 == 0) {
save_to_db();
}
setTimeout(tick, 0); // Queue a callback on next(ish) event loop cycle
}());
let i = 0;
tick();
@ T.J。人群,主席先生,谢谢您的回答。但是您上面的代码和下面的代码有什么区别?
var i = 0;
function tick() {
++i;
if (i%100 == 0) {
save_to_db();
}
setTimeout(tick, 0); // Queue a callback on next(ish) event loop cycle
}
tick();
答案 0 :(得分:1)
As VLAZ says,我想知道为什么需要无限循环,而不仅仅是使用事件循环。
我认为这是因为while循环是无限且同步的。因此,它没有给nodejs运行事件循环的机会。
是的,您完全正确。
不知道save_to_db
的工作原理很难回答这个问题,但是一般来说,您有以下三种选择:
使用一系列链接的setTimeout
(或setImmediate
)回调。
setTimeout
安排下一个工作块。使用async
函数和await
(如果save_to_db
返回承诺,或者可以对其进行修改以返回承诺)。
使用worker thread,它在应该执行save_to_db
时将消息发布到主线程(然后,阻塞工作线程的事件循环不会阻止主线程上的事件save_to_db
所需)。 (我可能不会为此使用工人。)
#1大致如下:
let i = 0;
(function tick() {
++i;
if (i == 100) {
save_to_db();
}
setTimeout(tick, 0); // Queue a callback on next(ish) event loop cycle
}());
请注意,Node.js设置了限时计时器,因此setTimeout(tick, 0)
不一定会在下一个事件循环迭代中安排下一个调用。您可以改用setImmediate
,因为它
计划在I / O事件的回调之后“立即”执行回调。
例如,此代码:
let i = 0;
let last = Date.now();
let sum = 0;
(function tick() {
++i;
sum += Date.now() - last;
if (i < 1000) {
last = Date.now();
setTimeout(tick, 0);
} else {
console.log(`Average: ${sum / i}`);
}
})();
报告在Linux机器上安装Node v12.4的平均经过时间为1.155ms。使用setImmediate
的等效代码报告的平均时间仅为0.004ms。
您在评论中说过,您不理解如何在“块”中实现这一点。这是一个示例:
const chunkSize = 1000; // Or whatever
let i = 0;
(function chunk() {
const chunkEnd = i + chunkSize;
while (i++ < chunkEnd) {
if (/*time to save to the DB*/) {
// Note that we don't wait for it to complete, you've said it's
// okay not to wait and that it's okay if they overlap
save_to_db();
}
}
setImmediate(chunk, 0);
})();
这样做,它将在主线程上完成大量工作,然后产生以允许处理save_to_db可能需要的任何I / O回调,然后继续进行。您可以对其进行一些优化,以仅在知道save_to_db
仍有工作要做时才退让,但这可能是对其进行了过度设计。
#2大致如下:
(async () => {
try {
let i = 0;
while (true) {
if (i == 100) {
await save_to_db();
}
}
} catch (e) {
// Handle/report error
}
})();
#3我将留给读者练习,但我可能不会为此使用工人。