简体   繁体   English

Webworker的递归功能

[英]Webworker for a recursive function

I have already some elements for my answer, coming from an old post ( Trying to implement inline Webworker for a recursive function ). 我的答案已经有一些内容了,来自一个老帖子( 试图为递归函数实现内联Webworker )。

Now I take over this little code implying this issue. 现在,我接管暗示此问题的小代码。 This little code uses inline webworkers since I use a recursive function which computes the best hit to play (this is the "computer" Hit). 这个小代码使用了内联网络工作人员,因为我使用了递归函数来计算最佳的匹配(这是“计算机”匹配)。 If I don't use webworker and I take a depth too high, the game is hanging in browser. 如果我不使用webworker,但深度太高,则说明游戏已在浏览器中挂起。

the source of code is available on [this link][1] 代码源可在[此链接] [1]上找到。

I would like to get a working code. 我想要一个有效的代码。 Indeed, I am near to the solution since several bugs have been fixed (for example, the fact to include different functions in webworker to make it do its computations without calling external functions. If I don't include all necessary functions, the webworker will not be able to work since it has its own scope. 确实,我已经解决了这个问题,因为已经修复了多个错误(例如,事实是在webworker中包含了不同的功能,从而可以在不调用外部函数的情况下进行计算。如果我不包括所有必需的功能,则webworker会由于它有自己的范围,因此无法工作。

So I would like to get help to debug my current version. 因此,我想获得调试当前版本的帮助。

The game is available on [this link][2] I am interested only into "computer vs player" mode (black begins to play). 该游戏可以在[此链接] [2]上使用。我仅对“计算机与玩家”模式感兴趣(黑色开始玩)。 Here below you can find the part when I call the recursive function. 在下面,您可以在我调用递归函数时找到该零件。

Once computation is done with this recursive function, I would like to get back the object representing the current map of game (positions of black/white circles). 使用此递归函数完成计算后,我想取回代表当前游戏地图(黑/白圆圈位置)的对象。

To get back the object or the coordinates suggested for hit (Here we are in main function), I did the following code : 为了找回建议的命中对象或坐标(这里是主函数),我做了以下代码:

// 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');
  }

and below the recursive function (inside inline webworker part ) : 并在递归函数下方(内联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();
    }

I expect to get back the coordinates "a" and "b" of computed value by recursive function but it seems to return nothing. 我希望通过递归函数取回计算值的坐标“ a”和“ b”,但似乎什么也没返回。

I don't know how to receive the object HitTemp object or more directly get a and b suggested coordinates ? 我不知道如何接收对象HitTemp对象或更直接获取ab建议的坐标?

Feel free to ask me more precisions if you don't understand my problem in this algorithm. 如果您不了解我在此算法中遇到的问题,请随时问我更多的精度。

There are two problems with the code that you presented: 您提供的代码有两个问题:

Problem #1: Assuming that postMessage passes a reference, but instead it serializes/deserializes it. 问题1:假设postMessage传递了一个引用,但是它对它进行了序列化/反序列化。

When you are using postMessage from within main js into the WebWorker, you are passing the HitTemp object, and later on, in the WebWorker you assume, that if you set properties of that object, the the original object would be modified as well. 当您从主要js内部将postMessage使用到WebWorker中时,您将传递HitTemp对象,然后再在WebWorker中假定,如果您设置了该对象的属性,则原始对象也将被修改。 By that I mean the following code: 我的意思是以下代码:

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;
    }
//...

Unfortunately, according to the documentation , when calling postMessage , the original object is serialized by the caller and then deserialized in the WebWorker, so effectively, the WebWorker is operating on a copy. 不幸的是,根据文档 ,在调用postMessage ,原始对象由调用者序列化,然后在WebWorker中反序列化,因此,WebWorker如此有效地在副本上进行操作。 Fortunately, this can be easily avoided by posting the data you are most interested in inside the postMessage back from the WebWorker. 幸运的是,可以通过将您最感兴趣的数据从WebWorker发回postMessage内来轻松避免这种情况。

Problem #2 : Using the a and b variables outside the scope 问题2:在范围外使用ab变量

I noticed that you are trying to access values that are defined in the .then() result callback outside that callback, like so: 我注意到您正在尝试访问该回调之外的.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');
}

Solution

To solve the first problem you need to return the values of HitCurrent (which contain coordPlayable that you are probably most interested in) with the postMessage back from the WebWorker. 为了解决第一个问题,你需要返回的值HitCurrent (包含coordPlayable与那你可能最感兴趣的) postMessage从WebWorker回来。 For the second problem, just move the final for loop using the a and b variables inside the .then() callback. 对于第二个问题,只需使用.then()回调内的ab变量移动最终的for循环即可。 The result code is as follows: 结果代码如下:

Main js code: 主要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');
    }
} );

WebWorker: WebWorker:

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();
}

I decided to return the whole HitCurrent from inside the WebWorker and passed is as HitResult parameter, because based on the fact that other parameters are modified by the recursive method as well (like arrayPlayable and arrayCurrent ), then you would also be able to get the modified values after the calculation. 我决定从WebWorker内部返回整个HitCurrent ,并将其作为HitResult参数传递,因为基于其他参数也被递归方法修改的事实(例如arrayPlayablearrayCurrent ),那么您还可以获取计算后修改值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM