5

これは node.js です。

いくつかの条件が満たされると無限ループになる関数があります。信頼できないユーザーがこれらの条件を設定しているため、この質問の目的のために、無限ループは修正不可能であると想定してください。

それでも、無限ループを止める方法が必要です。

これが私がやろうとしていることのサンプルコードです:

var infiniteloop = false;
var condition = true
function loop () {
  while (condition) {
    console.log('hi')
    if (infiniteloop) {
      condition = false
      console.log('oh last one')
    }
  }
}

loop()

だから私がやろうとしていることに基づいていくつかの質問。

  1. infiniteloop変数がtrueに設定されている場合、ループは正しく停止しますか?
  2. 無限ループを検出するにはどうすればよいですか? 3秒ごとにチェックするものがいいでしょう。
  3. infiniteloop同じプロセス上にある場合、ループ中に変数を変更することはできません。変数を別のプロセスに保存する必要がありますか?
  4. 無限ループを検出したものは、別のプロセスに存在する必要がありますか? 理想的には同じプロセスがいいでしょうが、何がうまくいきますか?

ご協力いただきありがとうございます。

4

6 に答える 6

5

他の提案の組み合わせに基づくソリューション:

function Worker()
{
    this.MaxIterations = 1000000;
    this.Enabled = true;    
    this.condition = true;
    this.iteration = 0;
    this.Loop = function()
    {
        if (this.condition 
            && this.Enabled 
            && this.iteration++ < this.MaxIterations)
        {
            console.log(this.iteration);
            setTimeout(this.Loop.bind(this),0);
        }
    };  
    this.Stop = function()
    {
        this.Enabled = false;
    };
}
var w = new Worker();
setTimeout(w.Loop.bind(w), 0);
setTimeout(w.Stop.bind(w), 3000);

これが最適かどうかはわかりませんが、期待どおりに機能するはずです。

setTimeoutを使用してループを再開すると、メインのnode.jsイベントループでw.Stopなどの他のイベントを処理できます。

于 2012-07-13T21:47:39.507 に答える
2

この場合の無限は、ループの最大反復回数がどうなるか次第です。このコードは JavaScript のシングル スレッドの性質をブロックしているため、Web ワーカーを使用していない限り、とにかくすべてがロックされます。このコードはとにかく間隔またはタイムアウトの実行をブロックするため、x 秒ごとにチェックしない方がよいでしょう。むしろ、ループ反復の最大しきい値としてループ自体に含めます。

var infiniteloop = false;
var condition = true;
var loopCounter = 1;
var maxLoopIterations = 1000; 
function loop () {
  while (condition) {
    console.log('hi');
    infiniteLoop = (loopCounter >= maxLoopIterations); 
    if (infiniteloop) {
      condition = false;
      console.log('oh last one');
      break;
    }
    loopCounter++;
  }
}
于 2012-07-13T18:33:28.240 に答える
2

実際、無限ループを止める必要はありません。使用するsetImmediate

例えば:

var immediateId;

function loop () {
    console.log('hi');
    immediateId = setImmediate(loop);
}

loop();

このコードのチャンクは、停止するまでhiを言い続けます。

//stop the loop:
clearImmediate(immediateId);

なぜ使うのかsetImmediate

  1. メモリ消費量が低く保たれているため、メモリ リークは発生しません。
  2. をスローしませんRangeError: Maximum call stack size exceeded
  3. パフォーマンスは良好です。

さらに、

無限ループを簡単に管理するために、このモジュールを作成しました。

var util = require('util');
var ee = require('events').EventEmitter;

var Forever = function() {
    ee.call(this);
    this.args = [];
};

util.inherits(Forever, ee);

module.exports = Forever;

Forever.prototype.add = function() {
    if ('function' === typeof arguments[0]) {
        this.handler = arguments[0];
        var args = Array.prototype.slice.call(arguments, 1);
        if (args.length > 0) {
            this.args = args;
        }
    } else {
        this.emit('error', new Error('when using add function, the first argument should be a function'));
        return 0;
    }
    return this;
};

Forever.prototype.run = function() {
    var handler = this.handler;
    var args = this.args;
    var that = this;

this._immediateId = setImmediate(function() {
        if (typeof handler === 'function') {

            switch (args.length) {
                // fast cases
                case 0:
                    handler.call(that);
                    that.run();
                    break;
                case 1:
                    handler.call(that, args[0]);
                    that.run();
                    break;
                case 2:
                    handler.call(that, args[0], args[1]);
                    that.run();
                    break;
                    // slower
                default:
                    handler.apply(that, args);
                    that.run();
            }
                } else {
                //no function added
                that.emit('error', new Error('no function has been added to Forever'));
            }
        });
};

Forever.prototype.stop = function() {
    if (this._immediateId !== null) {
        clearImmediate(this._immediateId);
    } else {
        this.emit('error', new Error('You cannot stop a loop before it has been started'));
    }
};

Forever.prototype.onError = function(errHandler) {
    if ('function' === typeof errHandler) {
        this.on('error', errHandler);
    } else {
        this.emit('error', new Error('You should use a function to handle the error'));
    }
    return this;
};

使用例:

var Forever = require('path/to/this/file');
var f = new Forever();

// function to be runned
function say(content1, content2){
    console.log(content1 + content2);
}

//add function to the loop
//the first argument is the function, the rest are its arguments
//chainable api
f.add(say, 'hello', ' world!').run();

//stop it after 5s
setTimeout(function(){
    f.stop();
}, 5000);

それでおしまい。

于 2013-05-27T06:43:14.897 に答える