В настоящее время невозможно использовать реализацию webgl на web-работнике, так как offlineCanvas является экспериментальной функцией.Тем не менее, можно использовать внутренний процессор.
Вот пример делегирования веб-работнику для выполнения вычисления
<head>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@0.14.2/dist/tf.min.js"></script>
<script>
const worker_function = () => {
onmessage = () => {
console.log('from web worker')
this.window = this
importScripts('https://cdn.jsdelivr.net/npm/setimmediate@1.0.5/setImmediate.min.js')
importScripts('https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@0.10.3')
tf.setBackend('cpu')
const res = tf.zeros([1, 2]).add(tf.ones([1, 2]))
res.print()
postMessage({res: res.dataSync(), shape: res.shape})
};
}
if (window != self)
worker_function();
</script>
<script>
const worker = new Worker(URL.createObjectURL(new Blob(["(" + worker_function.toString() + ")()"], { type: 'text/javascript' })));
worker.postMessage({});
worker.onmessage = (message) => {
console.log('from main thread')
const {data} = message
tf.tensor(data.res, data.shape).print()
}
</script>
</head>
С тензорами данные, разделяемые между основным потоком и веб-работником, могут быть большими.Эти данные либо клонированы, либо переданы.
Разница в том, что если данные будут клонированы, веб-работник все равно будет хранить копию данных для дальнейшей обработки.При передаче право собственности на данные также передается.Его преимущество по сравнению с клонированием заключается в быстроте передачи, фактически ее можно рассматривать как переход к ссылке (если исходят из языка с указателем)
Давайте обсудим производительность с этими двумя фрагментами
<head>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@0.14.2/dist/tf.min.js"></script>
<script>
const worker_function = () => {
onmessage = () => {
console.log('from web worker')
this.window = this
importScripts('https://cdn.jsdelivr.net/npm/setimmediate@1.0.5/setImmediate.min.js')
importScripts('https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@0.10.3')
tf.setBackend('cpu')
const res = tf.randomNormal([2000, 2000, 3])
const t0 = performance.now()
postMessage({res: res.dataSync().buffer, shape: res.shape}, [res.dataSync().buffer])
console.log(`Prediction took ${(performance.now() - t0).toFixed(1)} ms`)
};
}
if (window != self)
worker_function();
</script>
<script>
const worker = new Worker(URL.createObjectURL(new Blob(["(" + worker_function.toString() + ")()"], { type: 'text/javascript' })));
worker.postMessage({});
worker.onmessage = (message) => {
console.log('from main thread')
const {data} = message
tf.tensor(new Float32Array(message.data.res), message.data.shape)
}
</script>
</head>
<head>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@0.14.2/dist/tf.min.js"></script>
<script>
const worker_function = () => {
onmessage = () => {
console.log('from web worker')
this.window = this
importScripts('https://cdn.jsdelivr.net/npm/setimmediate@1.0.5/setImmediate.min.js')
importScripts('https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@0.10.3')
tf.setBackend('cpu')
const res = tf.randomNormal([2000, 2000, 3])
const t0 = performance.now()
postMessage({res: res.dataSync(), shape: res.shape})
console.log(`Prediction took ${(performance.now() - t0).toFixed(1)} ms`)
};
}
if (window != self)
worker_function();
</script>
<script>
const worker = new Worker(URL.createObjectURL(new Blob(["(" + worker_function.toString() + ")()"], { type: 'text/javascript' })));
worker.postMessage({});
worker.onmessage = (message) => {
console.log('from main thread')
const {data} = message
tf.tensor(message.data.res, message.data.shape)
}
</script>
</head>
Мы видим разницу в 10 мс между двумя фрагментами.Когда производительность стоит дорого, нужно учитывать, как данные распределяются, если они должны быть клонированы или переданы.