簡體   English   中英

您將如何限制遞歸函數?

[英]How would you throttle a recursive function?

假設我要運行一個遞歸函數,它將需要數周,數月甚至數年的時間才能完成。 它根據指定的參數返回字符串的所有可能排列。 當它運行時,我希望能夠看到它進展的程度-例如,到目前為止已經產生了多少排列。 簡而言之,我希望執行一個運行時間很長的遞歸函數而不鎖定我的UI。

另外,我想使用香草ES5( 不是嚴格模式)並且沒有WebWorkers來執行此操作。 它應該能夠在IE9中運行。

我所擁有的numspaces都可以正常使用,但是例如,當我將numspaces提高到10時,瀏覽器就會鎖定。 因此,我假設我只是在過於努力地使用瀏覽器,而“限制”它必須完成的工作量將有助於解決此問題。 我確實嘗試將setTimeout延遲從1增加到250,甚至1000,但是瀏覽器仍然鎖定。

我對此感興趣只是因為我嘗試這樣做,但是沒有。 另外,我知道一個事實,該代碼效率極低,並且有很多更好的方法可以完成我想要實現的目標。 所以推薦他們!

 var inputString = "abcdefghijklmnopqrstuvwxyz"; function allPossibleCombinations(input, length, curstr, callback) { if (curstr.length === length) return callback(curstr); (function(n) { setTimeout(allPossibleCombinations.bind(n, input, length, curstr + input[n], callback), 1); n++; if (n < input.length) setTimeout(arguments.callee.bind(n,n), 1); })(0); } var totalResults = 0, numDigits = inputString.length, numSpaces = 2, maxResults = Math.pow(numDigits, numSpaces), consoleElement = document.getElementById('console'), startTime = +new Date(); console.log("Starting.. expecting", maxResults, "total results..."); allPossibleCombinations(inputString.split(""), numSpaces, "", function(result) { totalResults++; if (totalResults === maxResults) { var elapsed = +new Date() - startTime; consoleElement.innerText = "Done."; console.log("Completed in", elapsed, "ms!"); } else { // Do something with this permutation... //... // Show progress... var progress = ((totalResults / maxResults) * 100).toFixed(2) * 1; consoleElement.innerText = progress + "%"; } }); 
 <div id="console"></div> 

您將很快接近setTimeout ,但是當前實現一次將所有計時器排入給定前綴的所有計時器中,從而導致計時器數量成倍增加,並且內存快速耗盡。 一個小的更改是創建另一個回調以指示完成,並使用它來等待遞歸調用,而永遠不要一次持有多個計時器:

 var inputString = "abcdefghijklmnopqrstuvwxyz"; function allPossibleCombinations(input, length, curstr, resultCallback, doneCallback) { if (curstr.length === length) { resultCallback(curstr); doneCallback(); return; } var n = 0; (function next() { if (n === input.length) { doneCallback(); return; } allPossibleCombinations( input, length, curstr + input[n], resultCallback, function () { n++; setTimeout(next, 0); }); })(); } var totalResults = 0, numDigits = inputString.length, numSpaces = 4, maxResults = Math.pow(numDigits, numSpaces), consoleElement = document.getElementById('console'), startTime = +new Date(); console.log("Starting.. expecting", maxResults, "total results..."); allPossibleCombinations( inputString.split(""), numSpaces, "", function (result) { totalResults++; // Do something with this permutation... //... // Show progress... var progress = ((totalResults / maxResults) * 100).toFixed(2) * 1; consoleElement.innerText = progress + "%"; }, function () { var elapsed = +new Date() - startTime; consoleElement.innerText = "Done."; console.log("Completed in", elapsed, "ms!"); }); 
 <div id="console"></div> 

不過,那確實很慢。 考慮如何將其編寫為生成器:

function* strings(input, length, current) {
    if (current.length === length) {
        yield current;
        return;
    }

    for (let i = 0; i < input.length; i++) {
        yield* strings(input, length, current + input[i]);
    }
}

並將其轉換為由回調負責恢復生成的系統:

function strings(input, length, current, yield_, continue_) {
    if (current.length === length) {
        yield_(current, continue_);
        return;
    }

    var i = 0;

    (function next() {
        if (i === input.length) {
            continue_();
            return;
        }

        strings(input, length, current + input[i++], yield_, next);
    })();
}

您可以隨意設置計時器,以提高性能。

 "use strict"; function countSequences(n, k) { var result = 1; for (var i = 0; i < k; i++) { result *= n--; } return result; } function strings(input, length, current, yield_, continue_) { if (current.length === length) { yield_(current, continue_); return; } var i = 0; (function next() { if (i === input.length) { continue_(); return; } var c = input[i++]; strings(input.replace(c, ''), length, current + c, yield_, next); })(); } var inputString = "abcdefghijklmnopqrstuvwxyz"; var totalResults = 0; var numDigits = inputString.length; var numSpaces = 5; var maxResults = countSequences(numDigits, numSpaces); var consoleElement = document.getElementById('console'); var startTime = +new Date(); console.log("Starting… expecting", maxResults, "total results."); strings( inputString, numSpaces, "", function (result, continue_) { if (totalResults++ % 1000 === 0) { var progress = (totalResults / maxResults * 100).toFixed(2); consoleElement.innerText = progress + "% (" + result + ")"; setTimeout(continue_, 0); } else { continue_(); } }, function () { var elapsed = +new Date() - startTime; consoleElement.innerText = "Done."; console.log("Completed in", elapsed, "ms!"); }); 
 <div id="console"></div> 

(這種風格仍然不是最佳,但它永遠不會結束的26 10,無論個人操作有多快,是。)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM