【问题标题】:Interrupting while() and finalizing gracefully Node.js中断 while() 并优雅地完成 Node.js
【发布时间】:2016-01-16 15:13:48
【问题描述】:

我正在为旅行商问题实施随机抽样/蒙特卡罗启发式算法。 我想执行最大的c 迭代,同时能够通过 Ctrl+C 或将SIGINT 发送到我的进程来停止搜索。

我知道之前有人问过这个问题(相关:Quitting node.js gracefully),但给定的解决方案对我不起作用。当我给 Ctrl+C 时,该过程不会退出,如果我杀死它,则不会执行最终代码。

我的代码:

var tsp = require("./Tsp.js");
var data = tsp.load("./input/it16862.tsp");

var starting_point = data.splice(10927, 1)[0];
var c = 0;
var cost = Number.POSITIVE_INFINITY;
var new_cost, solution, candidate_solution;
var interrupt = false;
var c = 0, interrupt = false;

process.on('SIGINT', function() {
    interrupt = true;
});

while(c < 1000000000) {
    if (interrupt) {
        break;
    }
    candidate_solution = shuffle(data);
    new_cost = tsp.cost(candidate_solution, starting_point);
    if (new_cost < cost) {
        cost = new_cost;
        solution = candidate_solution;
        console.log("Found a new better solution! %d", cost);
    }
    c++;
}

if (interrupt) {
    console.log("Caught interrupt signal");
}
console.log("Examined %d solutions", c);
console.log("Best: %j", cost);
console.log("Solution written to: %s", tsp.write(solution, starting_point, cost));

我在Ubuntu 14.04.1Nodejs 4.2.4。知道可能出了什么问题吗?

【问题讨论】:

  • 好问题。 process.on('SIGINT' ... 正是我想要的。

标签: javascript node.js


【解决方案1】:

JavaScript 是一种单线程语言,因此运行时无法像这样在 while 循环中中断进程。 process.on 处理函数在主事件循环空闲之前不会被调用,直到c &gt;= 1000000000 才会发生,因为你永远不会屈服。

为了使其正常工作,您需要更改工作循环以偶尔返回到 Node.js 运行时,如下所示:

// ...
var c = 0, interrupt = false;
function doWork() {
  while(c < 1000000000) {
      if (interrupt) {
          break;
      }
      // yield every 10000 iterations to
      // allow the event loop to handle events
      if ((c % 10000) === 0) {
          setImmediate(doWork);
          return;
      }
      candidate_solution = shuffle(data);
      new_cost = tsp.cost(candidate_solution, starting_point);
      if (new_cost < cost) {
          cost = new_cost;
          solution = candidate_solution;
          console.log("Found a new better solution! %d", cost);
      }
      c++;
  }
}

doWork();

您可以通过为收益之间的迭代次数选择不同的值来调整性能与响应速度(较高的数字可以通过避免由收益引起的开销来提高性能,但会通过延长响应时间直到可以确认中断来降低响应速度)。

【讨论】:

  • 有趣的解释,绝对有道理,但我仍然无法让它工作,SIGINT 回调永远不会执行。
  • 有趣的是,如果我使用 setTimeout(doWork, 100); 而不是 process.nextTick(doWork) 它可以工作...
  • 对不起,我认为nextTick 的语义可能随着时间而改变(或者我的大脑坏了!)。我已经更新了答案以使用 setImmediate 代替它应该允许 I/O 发生。
猜你喜欢
  • 2010-12-10
  • 1970-01-01
  • 2011-10-20
  • 1970-01-01
  • 2013-12-13
  • 2012-01-15
  • 1970-01-01
  • 2016-09-13
  • 2015-08-21
相关资源
最近更新 更多