繁体   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