【问题标题】:A Non Blocking Event Loop in NodejsNodejs 中的非阻塞事件循环
【发布时间】:2017-06-16 16:09:31
【问题描述】:

我试图实现一个事件循环。循环的目的很简单:

  1. 如果队列不为空,则让任务成为队列中最早的条目。
  2. 处理任务
  3. 如果,任务生成返回值,缓存它。
  4. 检查队列中的任务。
  5. 如果队列不为空,则采用下一个任务作为当前任务上下文。
  6. 将缓存的返回值传递给新任务。

我在 Nodejs 中尝试了以下方式的实现:

function task(){
this.task = Array.prototype.shift.call(arguments);
this.state = 'unprocessed';
this.successCallback = null;
this.failureCallback = null;
}
task.prototype.afterThat = function(){
if(arguments.length > 1){
this.successCallback = Array.prototype.shift.call(arguments);
this.failureCallback = Array.prototype.shift.call(arguments);
}
}
task.prototype._loop = function(){
let ctx = this;
while(ctx.state === 'unprocessed'){ // Source of problem
    setImmediate(this.task, function(){
    // change ctx.state if needed
   }, function(){
   // change ctx.state to 'processed'
   });
 }
}

此实现与事件循环的区别如下:

  1. successCallback 可以实例化一个新任务作为其返回值,而不是维护一个任务数组,然后将其用作当前任务。
  2. 根据处理情况,任务状态必须改变(或者不改变,如果采用新的挂起任务,其状态为“未处理”)。

我认为问题在于 setImmediate 调用,它无法更改上下文状态,因为当前执行状态永远不会终止,并且会不断在事件队列中为同一任务添加新调用。

我希望我已经很好地解释了它,并感谢一些实施指南,以及我在理解事件队列时可能遇到的任何错误。

谢谢。

【问题讨论】:

  • 我建议更好地缩进你的代码。我相信您是在 task.prototype.afterThat 内部定义 task.prototype._loop
  • 您的while 循环是一个无限循环。 JS 是单线程的,因此由于您的 while 循环,其他任何东西都无法运行。完成运行任务后,您需要检查ctx.statesetImmediate() 没有阻塞。在你的while 循环完成之前它不会运行,这是一个无限循环,所以它永远不会完成。

标签: javascript node.js concurrency eventqueue


【解决方案1】:

您的while 循环是一个无限循环。 JS 是单线程的,因此在您的 while 循环完成之前,没有其他东西可以运行。因为没有其他东西可以运行,ctx.state 永远不会改变。因为ctx.state 永远不会改变,所以您的while 循环将永远运行。

每次循环运行时,它都会调用setImmediate() 来安排任务运行,但该任务在while 循环完成之前无法真正运行。因此,您陷入了僵局,您将堆积大量要运行的任务(最终可能会溢出某些系统资源)。

您需要在完成运行任务后检查ctx.state(可能在成功和失败回调中),而不是在这样的循环中。

setImmediate() 没有阻塞。您使用setImmediate() 安排的函数在您的while 循环完成之前不会运行,但while 循环永远不会找到它的条件,因此它永远不会停止,因为在while 循环完成之前没有其他东西可以运行。

相反,调用下一个任务并在完成后检查ctx.state。由于您没有展示或描述它的使用方式或您真正想要完成的工作,因此我不确定建议的最佳实施方式。如果您在这方面需要更多帮助,那么您需要向我们展示更多关于您想要完成的工作以及您希望如何使用这个类的信息。

我的猜测是,您可以使用 Promise 来完成您想要做的事情,而无需自己编写大量基础架构代码,因为 Promise 是用于排序异步任务的非常好的工具。


仅供参考,您的代码有几处问题,例如缺少右括号和括号。您发布的内容甚至无法正确解析,更不用说运行了。并且,请在发布时正确缩进代码。


【讨论】:

  • 我会记下这一点。谢谢你的建议。
  • @AbrarHossain - 如果这回答了您的问题或引导您找到答案,那么您可以通过单击对您帮助最大的答案旁边的绿色复选标记向社区表明这一点。这也将为您在堆栈溢出时获得一些声誉积分,以遵循正确的程序。
  • 非常感谢您的努力。我还有一个问题。如果我想在这段代码中添加一个互斥锁,比如在检查状态之前阻止 ctx 对象,那会有帮助吗?如果我的术语有些不对,请原谅
  • @AbrarHossain - node.js 中的 Javascript 是单线程的,因此不需要互斥体,也没有这样的东西。如果您尝试跨异步操作管理某些状态,则可以使用自己的 Javascript 状态变量。由于 nodejs Javascript 是单线程的,所以只使用常规变量是没有问题的。不需要互斥锁。而且,您不能在 Javascript 中“在检查状态之前阻止 ctx 对象”。没有这样的事情,也没有必要尝试这样做。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-08-20
  • 1970-01-01
  • 1970-01-01
  • 2018-03-27
  • 2013-08-16
相关资源
最近更新 更多