
Поскольку это синхронно, веб-работник никогда не отправляет запрос postMessage до тех пор, пока не будет успешно извлечен ответ из буфера общего массива. Однако я наблюдаю, что очень редко (после тысяч сообщений) SharedArrayBuffer имеет поврежденный ответ. Мне удалось усугубить проблему, поэтому она случается довольно часто с помощью этого воспроизводимого примера из 80 строк:
Код: Выделить всё
//////////////////// WORKER
function workerFn() {
const sab = new SharedArrayBuffer(1024 * 1024) // [0:4 Atomics.wait signal][4:8 data length][8:8+data length JSON data]
const vi32 = new Int32Array(sab); // View needed for Atomics.wait
const vui8 = new Uint8Array(sab); // View needed for TextDecoder
const sbuf = { sab, vi32, vui8 };
postMessage({ type: "sab", sab });
let pl = 0;
while (true) {
postMessage({ type: "sync", payload: pl++ });
// This ostensibly synchronously blocks until the first int32 of the SharedArrayBuffer changes
// The main thread is responsible for changing this value and calling Atomics.notify()
Atomics.wait(sbuf.vi32, 0, 0); // Wait for expected value to change
Atomics.store(sbuf.vi32, 0, 0); // Reset expected value to 0 for next iteration
// The data is JSON as utf-8 encoded uint8
let data_length = sbuf.vi32[1];
let data = new TextDecoder().decode(sbuf.vui8.slice(8, 8 + data_length)); // 8 byte offset for header
let m;
try {
m = JSON.parse(data);
} catch (e) {
// This should never happen, yet it does
throw new Error("How is this possible? Bad JSON:" + data);
}
if (m.cooldown > 0) {
// Since this should never change until the next postMessage, we should be able to wait on it
Atomics.wait(sbuf.vi32, 0, 0, m.cooldown); // Sometimes this returns something other than "timed-out" which should be impossible!
}
}
}
//////////////////// MAIN THREAD
let processedMessages = 0;
function onWorkerMessage(workerName, data) {
if (data.type === 'sab') {
console.log('Received SAB from', workerName)
workers[workerName].sbuf = {
sab: data.sab,
vi32: new Int32Array(data.sab), // View needed for Atomics.store
vui8: new Uint8Array(data.sab), // View needed for TextEncoder
};
} else if (data.type === 'sync') {
processedMessages++;
if (processedMessages % 10000 === 0) {
console.log('Processed', processedMessages, 'messages')
}
// Do a little fake work
for (let i = 0; i < 100; i++)
Math.random();
// Send a message back to the worker
let m = { rv: data.payload % 2 === 0, cooldown: data.payload % 2 === 0 ? 0 : 0.5 };
const rui8 = new TextEncoder().encode(JSON.stringify(m));
const sbuf = workers[workerName].sbuf;
Atomics.store(sbuf.vi32, 1, rui8.length);
sbuf.vui8.set(rui8, 8);
// Signal the worker that the data is ready
Atomics.store(sbuf.vi32, 0, 1);
Atomics.notify(sbuf.vi32, 0);
}
}
//////////////////// INIT
let workers = {}
for (let i = 0; i < 20; i++) {
console.log('Starting worker', i)
let wf = workerFn.toString();
wf = wf.substring(wf.indexOf('{') + 1, wf.lastIndexOf('}'))
const blob = new Blob([wf], { type: 'application/javascript' })
const worker = new Worker(URL.createObjectURL(blob), { name: `worker${i}` })
worker.onmessage = e => onWorkerMessage(`worker${i}`, e.data)
workers[`worker${i}`] = worker
}
Код: Выделить всё
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
Код: Выделить всё
[img]https://i. sstatic.net/JpKYLj42.png[/img]
Такое поведение происходит как в Firefox, так и в Chrome.
Я просмотрел этот минимальный фрагмент для часов, и мне кажется, что он герметичен, что приводит меня к считаю, что это либо недоразумение с моей стороны, либо (менее вероятно) ошибка в самом JavaScript.
Еще одна подсказка: если я изменю код так, чтобы раздел восстановления имел следующее:
р>
Код: Выделить всё
if (m.cooldown > 0) {
// Since this should never change until the next postMessage, we should be able to wait on it
let rv = Atomics.wait(sbuf.vi32, 0, 0, m.cooldown);
if (rv !== 'timed-out') {
// !!! This should never happen, yet it does
throw new Error("How is this possible? Atomics.wait returned: " + rv);
}
}
Кроме того, удаление всего блока if (m.cooldown > 0) делает проблему невоспроизводимой, так что это явно суть, но я не понимаю, почему.
Подробнее здесь: https://stackoverflow.com/questions/793 ... ifesting-c
Мобильная версия