javascript - 用于递归函数的 Webworker

标签 javascript recursion web-worker

我的答案已经有一些元素,来自旧帖子 ( Trying to implement inline Webworker for a recursive function )。

现在我接手这段暗示这个问题的小代码。这段小代码使用内联网络 worker ,因为我使用递归函数来计算要播放的最佳命中(这是“计算机”命中)。如果我不使用 webworker 并且深度太高,游戏就会卡在浏览器中。

代码源可在[此链接][1]上找到

我想要一个工作代码。事实上,我已经接近解决方案,因为几个错误已经被修复(例如,在 webworker 中包含不同的函数以使其在不调用外部函数的情况下进行计算。如果我不包含所有必要的函数,webworker 将无法工作,因为它有自己的范围。

所以我想获得帮助来调试我当前的版本。

该游戏可在[此链接][2]上找到 我只对“计算机与玩家”模式感兴趣(黑色开始玩)。下面你可以找到我调用递归函数时的部分。

使用此递归函数完成计算后,我想返回代表游戏当前 map 的对象(黑/白圆圈的位置)。

为了取回建议命中的对象或坐标(这里我们在主函数中),我执行了以下代码:

// 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 }
            console.log('here5');
        }
        firstWorker.postMessage([HitTemp, HitTemp.playerCurrent, maxNodes]);
    } ).then( ( { result } ) => {
        //let [ a, b ] = result.coordPlayable;
        let [ a, b ] = HitTemp.coordPlayable;
        console.log('result3 : ', result);
        console.log('here3 : ', a, b);
    } );

  // HERE I TRY TO USE a and b in exploreHitLine function
  // who needs the variables a and b BUT I DON'T KNOW
  // IF a AND b ARE KNOWN HERE FROM CODE ABOVE

  for (k = 0; k < 8; k++) {
   exploreHitLine(HitCurrent, a, b, k, 'drawing');
  }

以及递归函数下方(内联 webworker 部分内):

window.onload = function() {

  // Inline webworker version
  workerScript = URL.createObjectURL( new Blob( [ `
  "use strict";

...
...
// All other variables and functions necessary for inline webworker
...
...
...


        function negaMax(HitCurrent, colorCurrent, depth) {
          // Indices
          var i, j, k;
          // Evaluation
          var arrayTemp, evalFinal, 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
          evalFinal = -infinity;
          // Compute all playable hits and check if playable hits
          if (computeHit(HitCurrent, 'playable')) {
            // 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 = -negaMax(JSON.parse(JSON.stringify(HitCurrent)), ((JSON.stringify(HitCurrent.playerCurrent) == JSON.stringify(playerBlack)) ? playerWhite : playerBlack), depth-1);
              if (e > evalFinal) {
                HitCurrent.coordPlayable = [i,j];
                evalFinal = e;
              }
              if (e == -infinity) {
                HitCurrent.coordPlayable = [i,j];
              }
              // Restore arrayCurrent array
              HitCurrent.arrayCurrent = JSON.parse(JSON.stringify(arrayTemp));
            }
            // Clean playable hits once double loop is done
            cleanHits('playable', HitCurrent);
          }
              console.log('here2 :', evalFinal);
          return evalFinal;
             }
        onmessage = function ( event ) {
          let params = event.data;
          //postMessage( { result: recursiveFunction(  HitCurrent, HitCurrent.playerCurrent, maxNodes ) } );
          postMessage( { result: negaMax( ...params ) } );
        };
        ` ], { type: "plain/text" } ) );

     main();
    }

我希望通过递归函数返回计算值的坐标“a”和“b”,但它似乎没有返回任何内容。

我不知道如何接收对象 HitTemp 对象或更直接获取 ab 建议坐标?

如果您不明白我在这个算法中的问题,请随时询问我更多的精度。

最佳答案

您提供的代码有两个问题:

问题#1:假设postMessage传递一个引用,但它会序列化/反序列化它。

当您使用postMessage时从主 js 到 WebWorker 中,您将传递 HitTemp 对象,稍后,在您假设的 WebWorker 中,如果您设置该对象的属性,则原始对象也会被修改。我的意思是下面的代码:

firstWorker.postMessage([
    HitTemp // <-- here you are sending the object to the WebWorker
, HitTemp.playerCurrent, maxNodes]);

workerScript = URL.createObjectURL( new Blob( [ `
// ...
    if (e > evalFinal) {
        HitCurrent.coordPlayable = [i,j]; // <-- here you access the object
        evalFinal = e;
    }
//...

不幸的是,根据documentation ,调用postMessage时,原始对象由调用者序列化,然后在 WebWorker 中反序列化,因此实际上,WebWorker 正在操作副本。幸运的是,通过将您最感兴趣的数据发布在 postMessage 中可以轻松避免这种情况。从 WebWorker 返回。

问题#2:使用ab范围之外的变量

我注意到您正在尝试访问 .then() 中定义的值该回调之外的结果回调,如下所示:

//...
} ).then( ( { result } ) => {
    let [ a, b ] = //here you define a and b
} );

// a and b are no longer in scope here
for (k = 0; k < 8; k++) {
    exploreHitLine(HitCurrent, a, b, k, 'drawing');
}

解决方案

要解决第一个问题,您需要返回 HitCurrent 的值(其中包含您可能最感兴趣的 coordPlayable)与 postMessage从 WebWorker 返回。对于第二个问题,只需移动最后的for使用 a 循环和b .then() 内的变量打回来。结果代码如下:

主要js代码:

new Promise( resolve => {
    let HitTemp = JSON.parse(JSON.stringify(HitCurrent));
    let firstWorker = new Worker( workerScript );
    firstWorker.onmessage = function ( event ) {
        resolve( event.data );
        console.log('here5');
    }
    firstWorker.postMessage([HitTemp, HitTemp.playerCurrent, maxNodes]);
} ).then( ( { result } ) => {
    var HitResult = result.HitResult;
    let [ a, b ] = HitResult.coordPlayable; // <-- get values from result
    console.log('result3 : ', result.eval);
    console.log('here3 : ', a, b);

    //move for loop inside the callback
    for (k = 0; k < 8; k++) {
        exploreHitLine(HitCurrent, a, b, k, 'drawing');
    }
} );

网络 worker :

window.onload = function() {

// Inline webworker version
workerScript = URL.createObjectURL( new Blob( [ `
"use strict";

// ...
function negaMax(HitCurrent, colorCurrent, depth) {
    // Indices
    var i, j, k;
    // Evaluation
    var arrayTemp, evalFinal, 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
    evalFinal = -infinity;
    // Compute all playable hits and check if playable hits
    if (computeHit(HitCurrent, 'playable')) {
        // 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 = -negaMax(JSON.parse(JSON.stringify(HitCurrent)).eval, ((JSON.stringify(HitCurrent.playerCurrent) == JSON.stringify(playerBlack)) ? playerWhite : playerBlack), depth-1); //since negaMax returns an object, don't forget to access the value in the recursive call

                    if (e > evalFinal) {
                        HitCurrent.coordPlayable = [i,j];
                        evalFinal = e;
                    }
                    if (e == -infinity) {
                        HitCurrent.coordPlayable = [i,j];
                    }
                    // Restore arrayCurrent array
                    HitCurrent.arrayCurrent = JSON.parse(JSON.stringify(arrayTemp));
                }
        // Clean playable hits once double loop is done
        cleanHits('playable', HitCurrent);
    }
    console.log('here2 :', evalFinal);
    return {eval: evalFinal, HitResult: HitCurrent }; //<-- send the additional HitCurrent as a result here
}
onmessage = function ( event ) {
    let params = event.data;
    postMessage( { result: negaMax( ...params ) } );
};
` ], { type: "plain/text" } ) );
main();
}

我决定退回整个HitCurrent从 WebWorker 内部传递并传递为 HitResult参数,因为基于其他参数也是通过递归方法修改的(如 arrayPlayablearrayCurrent ),那么计算后也能得到修改后的值。

关于javascript - 用于递归函数的 Webworker,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53904533/

相关文章:

javascript - AngularJS 意外共享作用域

正确的括号

c# - 需要递归查找。 DB 与 C# GUI

javascript - 如何优化动态加载 HTML5 游戏世界的 Canvas 渲染?

javascript - 创建一个基于当前平台的 Promise 对象

javascript - 添加 DOM 元素时获取通知

javascript - 当多个窗口打开时,如何避免多次写入相同的cookie

javascript - 遍历递归json树并合并

JavaScript Web Worker - close() 与 terminate()

javascript - Webworker OffscreenCanvas 绘制常规图像