是否有必要将 TensorFlow.js 计算放在 Node.js 工作线程中?

问题描述

我的问题是将 tensorflow.js 计算(使用 @tensorflow/tfjs-node)移动到 Node.js 中的工作线程是否是个好主意。这个问题归结为使用原生后端运行 TensorFlow 计算时主线程被阻塞到什么程度的问题。

据我所知,如果我使用完整的 JavaScript 版本的 TensorFlow (@tensorflow/tfjs) 并调用 model.fit(x,y,options),则适合模型的计算实际上发生在主 JavaScript 线程上。更准确地说,model.fit 返回一个 Promise,因此计算在微任务中异步执行,但那些仍然在主线程上运行。从某种意义上说,这些微任务是阻塞的,例如,事件处理程序的执行需要等待微任务队列清空。因此,在这种情况下,将计算转移到 Web Worker 以避免在计算进行时阻塞主线程是有意义的。

但是,如果我使用 TensorFlow 的原生版本 (@tensorflow/tfjs-node),“真正的工作”是在原生代码中进行的。这是我不知道的两件事,这使我无法回答标题中的问题:

  1. model.fit 背后的计算是否与主 JS 线程在同一线程上运行?
  2. 不管 1 的答案是什么,我们仍然有与 model.fit 的 promise 处理相关的微任务。在微任务队列中发生这种情况是否会阻止其他事件的处理,直到微任务队列为空?

这是我要问的一个例子:假设我有一个发送和接收 socket.io 消息的 Node.js 应用程序。这些消息之一是请求拟合 tensorflow.js 模型;当应用程序收到此消息时,它会调用 model.fit(x,options)。假设我没有将 TensorFlow 计算放在工作线程中,那么在计算过程中应用程序是否仍然可以回复来自服务器的 socket.io ping 消息?

解决方法

javascript 运行时将在主线程中运行所有代码,除非被告知使用工作线程。为了回答这个问题,@tensorflow/tfjs-node 发生的事情与浏览器中发生的事情没有什么不同。唯一的区别是计算的后端。虽然,promise 在微任务中运行,并不意味着阻塞事件循环,如果 promise 回调本身是一个 CPU 密集型操作,它将阻塞主线程。当有时可以观察到浏览器没有响应时,确实会发生这种情况。同样的事情也发生在 nodejs 上。

为了防止这些小问题,可以使用另一个工作人员来专门训练模型 (model.fit) 或预测 (model.predict)。这样,主线程将始终可用于处理其他处理。

在使用单个主线程的情况下,为了进一步解决这个问题,socket.io 消息将在到达时排队。但是只有在您的承诺完成后才会处理它们。当主线程已经开始执行 model.fit 时,它在 model.fit 解析之前将无法回复套接字消息。这就是使 workers 方便的原因。因为当工作人员忙于处理 model.fit 时,您的主线程被释放以处理事件循环中的任何其他传入消息