等待几个网络工作者完成

btt*_*btt 5 javascript web-worker

我有一个创建几个webworkers的脚本,这些webworkers执行一些工作并在完成后发送消息.

问题是我需要从所有这些结果中获取结果,然后计算最终解决方案.在其他工作中,他们计算出问题的部分解决方案,主线程使用这些部分解决方案来生成最终答案.

我怎么能等待所有这些线程完成,Javascript中是否有像Java中的invokeAll?

或多或少,我在主线程中的内容:

var data = [];

function createWorker(i) {
    var v = new Worker('js/worker.js');
    v.postMessage(i);
    v.onmessage = function(event){
        data.push(event.data);
    };
}

for(var i = 0; i < 100; i++) {
    createWorker(i);
}

//Wait until all have finished somehow
Run Code Online (Sandbox Code Playgroud)

T.J*_*der 8

收到最后一条数据后,请调用您的计算最终解决方案函数:

var data = [];

function createWorker(i) {
    var v = new Worker('js/worker.js');
    v.postMessage(i);
    v.onmessage = function(event){
        data.push(event.data);
        if (data.length === 100) {               // <====
            computeFinalSolution();              // <====
        }                                        // <====
    };
}

for(var i = 0; i < 100; i++) {
    createWorker(i);
}
Run Code Online (Sandbox Code Playgroud)

显然,参数化你认为必要的,但createWorker目前没有参数化i,所以...

请注意,条目data可能不是有序的.工人i == 0可能直到工人之后才完成i == 1,仅仅是因为线程调度的变幻莫测或者工作需要更多处理.如果你需要它们,它很容易完成,但我们必须添加一个计数器(或data在每次完成时循环检查):

var data = [];
var dataReceived = 0;

function createWorker(i) {
    var v = new Worker('js/worker.js');
    v.postMessage(i);
    v.onmessage = function(event){
        data[i] = event.data;                    // <====
        if (++dataReceived === 100) {            // <====
            computeFinalSolution();              // <====
        }                                        // <====
    };
}

for(var i = 0; i < 100; i++) {
    createWorker(i);
}
Run Code Online (Sandbox Code Playgroud)

如果你想要一种更现代,更灵活的方法,可以考虑使用promises,它是ES2015(又名ES6)的JavaScript原生版本,可以在旧的JavaScript引擎上使用polyfilled:

function createWorker(i) {
    return new Promise(function(resolve) {
        var v = new Worker('js/worker.js');
        v.postMessage(i);
        v.onmessage = function(event){
            resolve(event.data);
        };
    });
}

var promises = [];
for(var i = 0; i < 100; i++) {
    promises.push(createWorker(i));
}
Promise.all(promises)
    .then(function(data) {
        // `data` has the results, compute the final solution
    });
Run Code Online (Sandbox Code Playgroud)

这也有利于按顺序data包含结果,我们不必自己做这项工作.

以上内容符合您当前的代码,该代码似乎没有任何错误规定.但通常最好做错误处理:

function createWorker(i) {
    return new Promise(function(resolve, reject) {
        var v = new Worker('js/worker.js');
        v.postMessage(i);
        v.onmessage = function(event){
            // If you report errors via messages, you'd have a branch here for checking
            // for an error and either calling `reject` or `resolve` as appropriate.
            resolve(event.data);
        };
        // EITHER:
        v.onerror = reject; // Rejects the promise if an error is raised by the web worker, passing along the ErrorEvent
        // OR:
        v.onerror = function(event) {
            // Rejects the promise using the error associated with the ErrorEvent
            reject(event.error);
        };
    });
}

var promises = [];
for(var i = 0; i < 100; i++) {
    promises.push(createWorker(i));
}
Promise.all(promises)
    .then(function(data) {
        // `data` has the results, compute the final solution
    })
    .catch(function(error) {
        // something went wrong
    });
Run Code Online (Sandbox Code Playgroud)


小智 7

您可以向工人承诺,然后使用Promise.all

Promise.all(Array.from(Array(100), (x, i) => i).map(i => 
  new Promise((resolve, reject) => {
    const worker = new Worker('js/worker.js');
    worker.postMessage(i);
    worker.addEventListener('message', event => resolve(event.data));
    worker.addEventListener('error', reject);
  }))
  .then(results => ...);
Run Code Online (Sandbox Code Playgroud)