#node.js #puppeteer
#node.js #puppeteer
Вопрос:
Прежде чем я задам свой вопрос, я почти уверен, что ответ отрицательный, но все же нет ничего постыдного в том, чтобы спросить.
Я пытаюсь использовать THREE Puppeteer в качестве движка рендеринга на стороне сервера. Это означает, что я могу генерировать 3D-изображения в NodeJS, используя WebGL в безголовом браузере. Это работает идеально, за исключением производительности, которую я получаю от этого. И, к моему удивлению, узким местом является не 3D-рендеринг, а передача отрисованного изображения в NodeJS!
Рассмотрим следующий код:
const puppeteer = require('puppeteer');
const {
performance,
PerformanceObserver
} = require('perf_hooks');
const profiling = {};
const obs = new PerformanceObserver((list) => {
const entry = list.getEntries()[0];
if (profiling[entry.name]) {
profiling[entry.name].push(entry.duration);
} else {
profiling[entry.name] = [entry.duration];
}
});
obs.observe({entryTypes: ['measure'], buffered: false});
const pup = puppeteer.launch({
headless: true,
args: [
'--use-gl=swiftshader',
'--no-sandbox',
'--enable-surface-synchronization',
]
}).then(async browser => {
const page = (await browser.pages())[0];
await page.setViewport({width: 1280, height: 720});
await page.exposeFunction('mark', (name) => {
performance.mark(name);
});
await page.exposeFunction('measure', (name, start, end) => {
performance.measure(name, start, end);
});
//TODO: Load a web page or write a script to instantiate a scene
// using THREE.js (I've tested with WebGLRenderer)
for (let i=0; i<100; i ) {
window.mark('evaluate-init');
const txt = await page.evaluate(async () => {
window.mark('browser_context-init');
//Render your scene, you can also make a change to the scene just to make sure
// it will be rendered and you won't just be returning a cache.
renderer.render(scene, camera);
const canvas = renderer.domElement;
const txt = canvas.toDataURL("image/png");
window.mark('browser_context-end');
window.measure('browser_context', 'browser_context-init', 'browser_context-end');
return txt;
});
window.mark('evaluate-end');
window.measure('evaluate', 'evaluate-init', 'evaluate-end');
performance.mark("node_context-init");
const data = txt.replace(/^data:image/png;base64,/, "");
const png = Buffer.from(data, 'base64');
//TODO: You can do something with the png
performance.mark("node_context-end");
performance.measure("node_context", "node_context-init", "node_context-end");
}
const profiling_results = {};
for (let name of Object.keys(profiling)) {
const sum = profiling[name].reduce((a, b) => a b, 0);
const count = profiling[name].length;
const avg = (sum / count).toFixed(2);
profiling_results[name] = avg;
}
console.log(JSON.stringify(profiling_results, null, 2));
});
Основываясь на моих тестах, это средние значения для каждого раздела:
evaluate: 113.49 ms
browser_context: 0.16 ms
node_context: 5.29 ms
С моей точки зрения, 113,49 — 0,16 — это время, затраченное на передачу данных из безголового браузера в память NodeJS. И, как вы можете видеть, это основная часть времени, затраченного на сегодняшний день.
Теперь, после всего этого, мой вопрос таков: могу ли я каким-либо образом улучшить производительность передачи данных между Puppeteer и NodeJS?
Комментарии:
1. Я предполагаю, что есть некоторые накладные расходы на преобразование в строку и обратно …
canvas.getImageData()
улучшает ли это вообще?2. Хотя это происходит через протокол devtools (который, я думаю, через websocket), так что в любом случае может оказаться stringified.
3. Я выполнил более детальное профилирование, и большая часть времени, затраченного на самом деле, заключается в передаче данных из контекста браузера в контекст NodeJS. Кроме того, Puppeteer не поддерживает двоичные данные, что означает, что использование base64 неизбежно.
4. Какова ваша конечная цель? Может быть другой способ обойти браузер > мост узлов.
5. Это было бы здорово. Моя конечная цель в некоторой степени объясняется в вопросе. Я пытаюсь отобразить 3D-сцену и записать ее в прямой эфир (поддельная веб-камера). Но прямо сейчас частота кадров слишком низкая, а прямая трансляция составляет 5 кадров в секунду.