Javascript 中断while()并优雅地完成Node.js

Javascript 中断while()并优雅地完成Node.js,javascript,node.js,Javascript,Node.js,我正在为旅行推销员问题实施随机抽样/蒙特卡罗启发式。 我希望执行最大限度的c迭代,同时可以在需要时通过Ctrl+c或向进程发送SIGINT停止搜索 我知道以前有人问过这个问题(相关:),但给出的解决方案不适合我。当我给出Ctrl+C时,进程不会退出,如果我杀死它,则不会执行最终代码 我的代码: var tsp = require("./Tsp.js"); var data = tsp.load("./input/it16862.tsp"); var starting_point = data.

我正在为旅行推销员问题实施随机抽样/蒙特卡罗启发式。 我希望执行最大限度的
c
迭代,同时可以在需要时通过Ctrl+c或向进程发送
SIGINT
停止搜索

我知道以前有人问过这个问题(相关:),但给出的解决方案不适合我。当我给出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));
var tsp=require(“./tsp.js”);
var数据=tsp.load(“./input/it16862.tsp”);
var起点=数据拼接(10927,1)[0];
var c=0;
var成本=数量。正无穷大;
var新成本、解决方案、候选解决方案;
var中断=假;
变量c=0,中断=false;
process.on('SIGINT',function(){
中断=真;
});
而(c<100000000){
如果(中断){
打破
}
候选解决方案=洗牌(数据);
新成本=tsp成本(候选解决方案,起点);
如果(新成本<成本){
成本=新成本;
解=候选解;
log(“找到了新的更好的解决方案!%d”,成本);
}
C++;
}
如果(中断){
日志(“捕捉到的中断信号”);
}
控制台日志(“已检查%d个解决方案”,c);
console.log(“最佳:%j”,成本);
console.log(“解决方案写入:%s”,tsp.write(解决方案、起点、成本));

我现在使用的是Ubuntu 14.04.1,
节点4.2.4
。你知道什么是错的吗?

JavaScript是一个单线程语言,所以运行时不能中断在<代码>中间的进程,而循环是这样的。在主事件循环空闲之前,

process.on
处理程序函数将不会被调用,而在
c>=100000000
之前,这不会发生,因为您永远不会屈服

为了使其正常工作,您需要更改工作循环,以便偶尔返回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();
/。。。
变量c=0,中断=false;
函数doWork(){
而(c<100000000){
如果(中断){
打破
}
//每10000次迭代产生一个
//允许事件循环处理事件
如果((c%10000)==0){
立竿见影(道工);
返回;
}
候选解决方案=洗牌(数据);
新成本=tsp成本(候选解决方案,起点);
如果(新成本<成本){
成本=新成本;
解=候选解;
log(“找到了新的更好的解决方案!%d”,成本);
}
C++;
}
}
销钉();

您可以通过为两个产量之间的迭代次数选择不同的值来调整性能与响应性(更高的数值可以通过避免产量造成的开销来提高性能,但通过延长确认中断所需的时间来降低响应性)。

有趣的解释,显然是有意义的,但我仍然无法让它工作,因此从未执行
SIGINT
回调而不是
process.nextTick(doWork)
它可以工作…很抱歉,我认为
nextTick
的语义可能随着时间的推移而改变(或者我的大脑坏了!)。我已经更新了答案,改为使用
setImmediate
,它应该允许I/O发生。谢谢,相关的好问题。进程.on('SIGINT')…正是我想要的。