尝试为递归函数实现内联Webworker

时间:2018-04-16 23:44:09

标签: javascript recursion web-worker

我有一个使用Javascript的递归函数的第一个版本,它产生预期的结果。低于工作版本:

// Call the recursive function and get final (a,b) results
var HitTemp = JSON.parse(JSON.stringify(HitCurrent));
var result= recursiveFunction(HitTemp, HitTemp.playerCurrent, maxNodes);
var a = HitTemp.coordPlayable[0];
var b = HitTemp.coordPlayable[1];

// Recursive function
function recursiveFunction(HitCurrent, colorCurrent, depth) {
 // Indices
 var i, j, k;
 // Evaluation
 var arrayTemp, eval, e;
 // Set current color to HitCurrent
 HitCurrent.playerCurrent = colorCurrent;
 // Deep copy of arrayCurrent array
 arrayTemp = JSON.parse(JSON.stringify(HitCurrent.arrayCurrent));
 // If depth equal to 0
 if (depth == 0)
  return evaluation(HitCurrent);
 // Starting evaluation
 eval = -infinity;
 // Browse all possible hits
 for (i = 0; i < 8; i++)
  for (j = 0; j < 8; j++) {
   if (HitCurrent.arrayPlayable[i][j] == 'playable') {
    for (k = 0; k < 8; k++) {
     // Explore line started from (i,j) with direction "k"
     exploreHitLine(HitCurrent, i, j, k, 'drawing');
    }
    // Recursive call
    e = recursiveFunction(JSON.parse(JSON.stringify(HitCurrent)), ((JSON.stringify(HitCurrent.playerCurrent) == JSON.stringify(playerBlack)) ? playerWhite : playerBlack), depth-1);
    if (e > eval) {
     HitCurrent.coordPlayable = [i,j];
     eval = e;
    }
   }
   // Restore arrayCurrent array
   HitCurrent.arrayCurrent = JSON.parse(JSON.stringify(arrayTemp));
   }
 return eval;
}

由此,我想使用&#34; inline&#34; WebWorkers将递归专用于WebWorker并避免在浏览器中挂起进程。

我尝试关注this linkthis other link

我不知道我是否需要&#34; postmessage&#34;主线程的对象HitCurrent或值eval:通过使用WebWorker,我在return指令(返回终端案例中的值)和objet {{}之间产生混淆1}}参数传递给下一个递归调用。

如果有人可以通过使用内联网络工程师(或使用经典的网络工作方式)提供一些线索来重现这个原始算法。

2 个答案:

答案 0 :(得分:1)

内联webworker示例:

作为您的代码,没有function evaluationfunction exploreHitLine。 在使用以下代码之前,您必须将它们插入code

{
    let workerScript = URL.createObjectURL( new Blob( [ `
    "use strict";
    // Recursive function
    function recursiveFunction( HitCurrent, colorCurrent, depth ) {
        // Indices
        var i, j, k;
        // Evaluation
        var arrayTemp, eval, e;
        // Set current color to HitCurrent
        HitCurrent.playerCurrent = colorCurrent;
        // Deep copy of arrayCurrent array
        arrayTemp = JSON.parse(JSON.stringify(HitCurrent.arrayCurrent));
        // If depth equal to 0
        if ( depth === 0 ) return evaluation(HitCurrent);
        // Starting evaluation
        eval = -infinity;
        // Browse all possible hits
        for (i = 0; i < 8; i++) {
            for (j = 0; j < 8; j++) {
                if (HitCurrent.arrayPlayable[i][j] === 'playable') {
                    for (k = 0; k < 8; k++) {
                        // Explore line started from (i,j) with direction "k"
                        exploreHitLine(HitCurrent, i, j, k, 'drawing');
                    }
                    // Recursive call
                    e = recursiveFunction(JSON.parse(JSON.stringify(HitCurrent)), ((JSON.stringify(HitCurrent.playerCurrent) == JSON.stringify(playerBlack)) ? playerWhite : playerBlack), depth-1);
                    if (e > eval) {
                        HitCurrent.coordPlayable = [i,j];
                        eval = e;
                    }
                }
                // Restore arrayCurrent array
                HitCurrent.arrayCurrent = JSON.parse(JSON.stringify(arrayTemp));
            }
        }
        return eval;
    }
    onmessage = function ( event ) {
        let params = event.data;
        postMessage( { result: recursiveFunction( ...params ) } );
    }
        ` ], { type: "plain/text" } ) );


    // Call the recursive function and get final (a,b) results
    new Promise( resolve => {
        let HitTemp = JSON.parse(JSON.stringify(HitCurrent));
        let firstWorker = new Worker( workerScript );
        firstWorker.onmessage = function ( event ) {
            resolve( event.data ); //{ result: XXX }
        }
        firstWorker.postMessage( HitTemp, HitTemp.playerCurrent, maxNodes );
    } ).then( ( { result } ) => {
        let [ a, b ] = result.coordPlayable;
        console.log( result );
    } );
}

此外,以下是使用内联WebWorker:

{
    let workerScript = URL.createObjectURL( new Blob( [ `
    "use strict";
    onmessage = function ( event ) {
        let sum = 0, count = event.data;
        for ( let i = 0; i < count**count; i++ ) {
            sum += i;
        }
        postMessage( { result: sum, count } );
    }
    ` ], { type: "plain/text" } ) );
    let firstWorker = new Worker( workerScript );
    let firstAlive = setTimeout( () => {
        firstWorker.terminate();
        console.log( "terminated" );
    }, 3000 );
    firstWorker.onmessage = function ( event ) {
        clearTimeout( firstAlive );
        console.log( event.data );
    }
    firstWorker.postMessage( 10 );

    let secondWorker = new Worker( workerScript );
    let secondAlive = setTimeout( () => {
        secondWorker.terminate();
        console.log( "terminated" );
    }, 3000 );
    secondWorker.onmessage = function ( event ) {
        clearTimeout( secondAlive );
        console.log( event.data );
    }
    secondWorker.postMessage( 5 );

}

更新1。

{
    // Inline webworker version
    let workerScript = URL.createObjectURL( new Blob( [ `
    "use strict";
    // Recursive function
    function recursiveFunction( HitCurrent, colorCurrent, depth ) {
        // Indices
        var i, j, k;
        // Evaluation
        var arrayTemp, evaluated, e;
        // Set current color to HitCurrent
        HitCurrent.playerCurrent = colorCurrent;
        // Deep copy of arrayCurrent array
        arrayTemp = JSON.parse(JSON.stringify(HitCurrent.arrayCurrent));
        // If depth equal to 0
        if (depth == 0)
        return evaluation(HitCurrent);
        // Starting evaluation
        evaluated = -infinity;
        // Browse all possible hits
        for (i = 0; i < 8; i++) {
            for (j = 0; j < 8; j++) {
                if (HitCurrent.arrayPlayable[i][j] == 'playable') {
                    for (k = 0; k < 8; k++) {
                        // Explore line started from (i,j) with direction "k"
                        exploreHitLine(HitCurrent, i, j, k, 'drawing');
                    }
                    // Recursive call
                    e = recursiveFunction(JSON.parse(JSON.stringify(HitCurrent)), ((JSON.stringify(HitCurrent.playerCurrent) == JSON.stringify(playerBlack)) ? playerWhite : playerBlack), depth-1);
                    if ( e > evaluated ) {
                        HitCurrent.coordPlayable = [i,j];
                        evaluated = e;
                    }
                    if (e == -infinity) { HitCurrent.coordPlayable = [ i, j ]; }
                    // Restore arrayCurrent array
                    HitCurrent.arrayCurrent = JSON.parse(JSON.stringify(arrayTemp));
                }
            }
        }
        return evaluated;
    }

    onmessage = function ( event ) {
        let params = event.data;
        //postMessage( { result: recursiveFunction(  HitCurrent, HitCurrent.playerCurrent, maxNodes ) } );
        postMessage( { result: recursiveFunction( ...params ) } );
    };
    ` ], { type: "plain/text" } ) );


   // Call the recursive function and get final (a,b) results
    new Promise( resolve => {
        let HitTemp = JSON.parse(JSON.stringify(HitCurrent));
        let firstWorker = new Worker( workerScript );
        firstWorker.onmessage = function ( event ) {
            resolve( event.data ); //{ result: XXX }
        }
        firstWorker.postMessage( [ HitTemp, HitTemp.playerCurrent, maxNodes ] );
    } ).then( ( { result } ) => {
        let [ a, b ] = result.coordPlayable;
        console.log( result );
    } );
}

我的错误解释:

  1. 在“严格模式”下,不可能使用“eval”作为变量的名称。
  2. =&GT;

    来自:eval

    至:evaluated

    1. Worker.postMessage( aMessage, Transferrable ),在这种情况下,您不需要使用第二个参数。
    2. =&GT;

      来自:firstWorker.postMessage( HitTemp, HitTemp.playerCurrent, maxNodes );

      至:firstWorker.postMessage( [ HitTemp, HitTemp.playerCurrent, maxNodes ] );

      https://developer.mozilla.org/en-US/docs/Web/API/Worker/postMessage

      1. 继续2,将参数传递给recursiveFunction是固定的。

答案 1 :(得分:0)

  • eval是一个关键字;使用其他变量名称。
  • 仅限
  • postMessage 接受一个参数(它也接受一个transferable,但这不适用于你的情况),如果那个参数不是一个原始值,它应该 是一个可序列化的对象(例如,你不能传递函数 或直接向网络工作者的方法)

我可能误解了你想要做的事情,但你可能想重新考虑递归地产生未知的数量的网络工作者!只需生成一个 webworker并将函数的参数传递给它,并在该webworker内同步执行递归计算,而不需要生成新的worker,如果你只想释放主堆栈。产生过多的网络工作者将消耗大量资源,实际上会减慢你的计算速度!仅供参考,产生每个新的网络工作者需要大约40毫秒并占用资源。这是关于利用多线程计算递归函数的一般观察!这可能有所帮助: https://softwareengineering.stackexchange.com/questions/238729/can-recursion-be-done-in-parallel-would-that-make-sense

  

关于调用URL.createObjectURL(new Blob(...))块的所有函数,我是否必须将它们包含在此块中,或者我可以将它们写在它之外(正如您所说的评估和explotHitLine函数)?

您的webworker是一个完全独立的JS文件和执行上下文;您将无法访问未在其上下文中定义的任何内容或作为消息发送给它。

顺便说一下,您的代码中存在一些错误,无法正确编译:{{1​​}}应该是infinityInfinityplayerBlack未定义,等等