Я ничего не вижу в спецификации JavaScript , предложенных расширениях спецификации DOM , относящихся к SharedArrayBuffer
, или текущей спецификации WHAT-WG HTML предположить, что совместно используемая память будет синхронизироваться / обновляться между потоками, когда один поток отправляет сообщение другому, а другой обрабатывает сообщение.( После одна уже отправила общую память другой.) Однако я также не могу экспериментально проверить, что не не происходит (в моих тестах я нене вижу устаревших значений).Есть ли какая-то такая гарантия, что я упускаю, и если да, то где она гарантирована?Например, документировано ли это для postMessage
, и я пропустил это, или есть что-то о возвращении к циклу событий / очереди заданий, которое гарантирует это (поскольку обработка сообщения из другого потока включает в себя это) и т. Д.?Или, альтернативно, это определенно не гарантировано (и эта информация где-то в спецификации)?
Пожалуйста не спекулируйте и не делайте«разумное предположение».Я ищу точную информацию: цитаты из канонических источников, воспроизводимый эксперимент, который показывает, что это не гарантировано (хотя, я полагаю, тогда возникает вопрос, является ли это просто ошибкой реализации), такого рода вещи.
Ниже приведен источник для моих тестов, которые еще не смогли перехватить несинхронизированную память.Чтобы запустить его, вам нужно использовать браузер, который в настоящее время поддерживает SharedArrayBuffer
, что, на мой взгляд, в настоящий момент означает Chrome v67 или выше (Firefox, Edge и Safari все имели поддержку, но отключили его в ответ на Spectre и Meltdown.в январе 2018 года; Chrome сделал то же самое, но повторно включил его в v67 [июль 2018] на платформах, где включена их функция изоляции сайтов).
sync-test-postMessage.html
:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Sync Test postMessage</title>
</head>
<body>
<script src="sync-test-postMessage-main.js"></script>
</body>
</html>
sync-test-postMessage-main.js
:
const array = new Uint32Array(new SharedArrayBuffer(Uint32Array.BYTES_PER_ELEMENT));
const worker = new Worker("./sync-test-postMessage-worker.js");
let counter = 0;
const limit = 1000000;
const report = Math.floor(limit / 10);
let mismatches = 0;
const now = performance.now();
const log = msg => {
console.log(`${msg} - ${mismatches} mismatch(es) - ${performance.now() - now}ms`);
};
worker.addEventListener("message", e => {
if (e.data && e.data.type === "ping") {
++counter;
const value = array[0];
if (counter !== value) {
++mismatches;
console.log(`Out of sync! ${counter} !== ${value}`);
}
if (counter % report === 0) {
log(`${counter} of ${limit}`);
}
if (counter < limit) {
worker.postMessage({type: "pong"});
} else {
console.log("done");
}
}
});
worker.postMessage({type: "init", array});
console.log(`running to ${limit}`);
sync-test-postMessage-worker.js
:
let array;
this.addEventListener("message", e => {
if (e.data) {
switch (e.data.type) {
case "init":
array = e.data.array;
// fall through to "pong"
case "pong":
++array[0];
this.postMessage({type: "ping"});
break;
}
}
});
Используя этот код, если память не была синхронизирована, я бы ожидал, что в какой-то момент основной поток увидитустаревшее значение в общем массиве.Но вполне вероятно (на мой взгляд), что этот код работает только из-за относительно больших временных интервалов, связанных с передачей сообщений ...