Web Worker总是比主线程慢25%,在Canvas像素

时间:2017-12-11 17:02:44

标签: javascript html5 multithreading performance web-worker

我创建了一个简单的应用程序,它从video标记中获取照片并将其设置为灰色,在此处完整提供:Canvas WebWorker PoC

const photoParams = [         
    0, //x
    0, //y
    320, //width
    240, //height
];
async function startVideo () {
  const stream = await navigator.mediaDevices.getUserMedia({
      audio: false,
      video: true,
  });
  const video = document.querySelector('#video');
  video.srcObject = stream;
  video.play();
  return video;
}

function takePhoto () {
    const video = document.querySelector('#video');
    const canvas = document.querySelector('#canvas');
    canvas.width = 320;
    canvas.height = 240;
    const context = canvas.getContext('2d');
    context.drawImage(video, ...photoParams);

    const imageData = applyFilter({imageData: 
    context.getImageData(...photoParams)});
    context.putImageData(imageData, 0, 0);

    return canvas.toDataURL("image/png")
}

function setPhoto () {
    const photo = takePhoto();
    const image = document.querySelector('#image');
    image.src = photo;
}

startVideo();
const button = document.querySelector('#button');
button.addEventListener('click', setPhoto);

在其中一个函数中,我放置了一个很长的,不必要的for循环来使它变得非常慢:

function transformPixels ({data}) {
    let rawPixels;
    const array = new Array(2000);
    for (element of array) {
        rawPixels = [];
        const pixels = getPixels({
            data,
        });
        const filteredPixels = [];
        for (const pixel of pixels) {
            const average = getAverage(pixel);
            filteredPixels.push(new Pixel({
                red: average,
                green: average,
                blue: average,
                alpha: pixel.alpha,
            }));
        }
        for (const pixel of filteredPixels) {
            rawPixels.push(...pixel.toRawPixels());
        }
    }
    return rawPixels;
};

我创建了Web Worker版本,正如我所说,它应该更快,因为它不会破坏主线程:

function setPhotoWorker () {
    const video = document.querySelector('#video');
    const canvas = document.querySelector('#canvas');
    canvas.width = 320;
    canvas.height = 240;
    const context = canvas.getContext('2d');
    context.drawImage(video, ...photoParams);
    const imageData = context.getImageData(...photoParams);

    const worker = new Worker('filter-worker.js');
    worker.onmessage = (event) => {
        const rawPixelsArray = [...JSON.parse(event.data)];
        rawPixelsArray.forEach((element, index) => {
            imageData.data[index] = element;
        });
        context.putImageData(imageData, 0, 0);

        const image = document.querySelector('#image');
        image.src = canvas.toDataURL("image/png");
    }
    worker.postMessage(JSON.stringify([...imageData.data]));
}

可以这样运行:

button.addEventListener('click', setPhotoWorker);

工作人员代码与单线程版本几乎完全相同,除了一件事 - 提高消息传递性能,string is sent instead of array of numbers

worker.onmessage = (event) => {
    const rawPixelsArray = [...JSON.parse(event.data)];
};
//...
worker.postMessage(JSON.stringify([...imageData.data]));

filter-worker.js内:

onmessage = (data) => {
    const rawPixels = transformPixels({data: JSON.parse(data.data)});
    postMessage(JSON.stringify(rawPixels));
};

问题是 worker版本总是比主线程版本慢20-25%。首先,我认为这可能是消息的大小,但在我的笔记本电脑中,我有640 x 480相机,它提供了307 200件物品 - 我认为这些物品价格不够昂贵,因为2000 for迭代,导致结果:主线程:约160秒,工人约200秒。您可以从Github repo下载应用并自行查看。这里的模式非常相似 - 工人总是慢20-25%。如果不使用JSON API,工人需要220秒才能完成工作。我认为唯一的一个原因是工作线程的优先级非常低,而在我的应用程序中,主线程没有太多的事情要做,它只是速度慢 - 而在实际应用中,主线程可能比较繁忙,工人会赢。你有什么想法为什么工人这么慢?谢谢你的每一个答案。

0 个答案:

没有答案