如何在循环中等待多个WebWorkers

时间:2016-09-01 21:57:39

标签: javascript multithreading web-worker

我在JS中使用Web Workers存在以下问题。我有一个重型应用程序做一些模拟。代码在多个Web Workers中运行。 主线程正在WebPage上运行。但如果有意义的话,也可能是Web Worker。

示例:

    var myWebWorkers = [];
    function openWorker(workerCount){
        for(var i = 0; i < workerCount; i++){
            myWebWorkers[i] = new Worker('worker.js');
            myWebWorkers[i].onmessage = function(e){
                this.result = e.data;
                this.isReady = true;
            }
        }
    }

    function setWorkerData(somedata){
        // somedata.length is always a multiple of myWebWorkers.length
        var elementCntPerWorker = somedata.length / myWebWorkers.length;
        myWebWorkers.forEach(function(worker, index){
            worker.isReady = false;
            worker.postMessage(
                somedata.slice(index * elementCntPerWorker, 
                    (index + 1) * elementCntPerWorker - 1));
        });
    }

    var somedata = [...];
    openWorker(8); 
    for(var i = 0; i < 10000; i++){
         setWorkerData(somedata);
         waitUntilWorkersAreDoneButAllowBrowserToReact(myWebWorkers);
         if(x % 100) updateSVGonWebPage
    }

    function waitUntilWorkersAreDoneButAllowBrowserToReact(){
        /* wait for all myWebWorkers-onchange event, but
           allow browser to react and don't block a full Web Worker 
           Following example is my intension. But will not work, because 
           events are not executed until code excution stops.
        */
        somedata = [];
        for(var i = 0; i < myWebWorkers.length; i++){
            while(!myWebWorkers[i].isReady);
            somedata = somedata.concat(myWebWorkers.result);
        }
    }

我需要的是waitUntilWorkersAreDoneButAllowBrowserToReact函数或使其运行的概念。每次搜索都是以互斥,睡眠等方式结束,以下句子结束:&#34; JS是单线程&#34;,&#34;这只有在你不在循环中时才有效#34;,&#34;那里没有理由有睡眠功能&#34;。等

即使将主要任务传递给另一名工人,我也遇到了问题,如果其他人准备就绪,这个线程100%负责检查,这是浪费能源和处理能力。

我很想拥有像myWebWorker.waitForReady()这样的阻止功能,这样可以处理事件。这将使javascript更上一层楼。但也许我错过了一个简单的概念,就是这样做。

谢谢!

1 个答案:

答案 0 :(得分:3)

  

我很想拥有像myWebWorker.waitForReady()

这样的阻止功能

不,那是不可能的。您研究的所有语句都是正确的,Web工作者保持异步,并且只能通过消息进行通信。没有等待事件,甚至没有等待工作线程。

你会想要使用promises:

function createWorkers(workerCount, src) {
    var workers = new Array(workerCount);
    for (var i = 0; i < workerCount; i++) {
        workers[i] = new Worker(src);
    }
    return workers;
}
function doWork(worker, data) {
    return new Promise(function(resolve, reject) {
        worker.onmessage = resolve;
        worker.postMessage(data);
    });
}
function doDistributedWork(workers, data) {
    // data size is always a multiple of the number of workers
    var elementsPerWorker = data.length / workers.length;
    return Promise.all(workers.map(function(worker, index) {
        var start = index * elementsPerWorker;
        return doWork(worker, data.slice(start, start+elementsPerWorker));
    }));
}

var myWebWorkers = createWorkers(8, 'worker.js');
var somedata = [...];
function step(i) {
    if (i <= 0)
        return Promise.resolve("done!");
    return doDistributedWork(myWebWorkers, somedata)
    .then(function(results) {
        if (i % 100)
            updateSVGonWebPage();
        return step(i-1)
    });
}
step(1000).then(console.log);

Promise.all具有等待并发运行结果的神奇功能,step函数使用递归方法执行asynchronous looping