Node.js 主线程阻塞

Node.js main thread blocking

我正在进行人工智能训练,该方法需要很长时间(5 分钟),而我的方法是 运行 我的后端保持阻塞状态,等待我的方法完成,是否有解决方案?

train: (answersIA, search, res) => {
        const path = `api/IA/${search.id}`;

        if (answersIA.length == 0) {
            return null;
        }
        else {
            answersIA = answersIA.filter(answer => answer.score);
            answersIA = answersService.setOutput(answersIA);
            answersIA = answersService.encodeAll(IAServiceTrain.adjustSize(answersIA));
            net.train(answersIA, {
                errorThresh: 0.005,
                iterations: 100,
                log: true,
                logPeriod: 10,
                learningRate: 0.3
            });
            mkdirp(path, (err) => {
                if (err) throw 'No permission to create trained-net file';
                fs.writeFileSync(`${path}/trained-net.js`, `${net.toFunction().toString()};`);
                res.json({
                    message: 'Trained!'
                });
            });
        }
  }

https://whosebug.com/users/740553/mike-pomax-kamermans 所述,Javascript 是单线程的,这意味着长 运行 同步操作将在执行时阻塞您的线程。目前尚不清楚您使用哪个库来执行训练,但请检查他们是否有任何异步训练方法。此外,您正在使用 fs.writeFile 方法的同步版本,这将在执行时再次阻塞您的线程。要解决此问题,请使用异步版本:

fs.writeFile(`${path}/trained-net.js`, `${net.toFunction().toString()};`, function (err) {
  if (err) return console.log(err);
  console.log('File write completed');
}););

使用child_process对单独的进程进行训练。以下是它的实现方式:

trainMaster.js

const fork = require('child_process').fork;

exports.train = (arguments, callback) => {
    const worker = fork(`${__dirname}/trainWorker.js`);

    worker.send(arguments);

    worker.on('message', result => {
      callback(result);
      worker.kill();
    });
}

trainWorker.js

process.on('message', arguments => {
  const result = train(arguments)
  process.send(result);
});

function train(arguments) { /* your training logic */ }

因此,当您从主应用程序在 trainMaster.js 上调用 train 时,它不会进行实际训练,也不会阻止事件循环。相反,它会创建一个新进程,等待它执行所有繁重的工作,然后终止它。

如果同时训练的数量少于您机器上 CPU 的数量,这种方法应该可以正常工作。来自 Node.js 文档:

It is important to keep in mind that spawned Node.js child processes are independent of the parent with exception of the IPC communication channel that is established between the two. Each process has its own memory, with their own V8 instances. Because of the additional resource allocations required, spawning a large number of child Node.js processes is not recommended.

否则您将需要一些不同的方法,例如将工作人员分散到多台机器上并使用消息队列在他们之间分配工作。