Почему передаются буферы, стерилизованные в javascript?
Javascript позволяет переносить буферы из исходного потока в поток Worker. В противном случае массив ArrayBuffer будет скопирован, а затем передан работнику. Переданные буферы недоступны ( "стерилизованы" ) в исходном потоке [1]:
// create data that can be transfered
var arr = new Uint8Array(5);
// outputs: 5
console.log(arr.buffer.byteLength);
var worker = new Worker("some_worker.js");
// transfer the buffer
worker.postMessage({arr: arr}, [arr.buff]);
// the buffer vanishes. is "Neutered"
// outputs: 0
console.log(arr.buffer.byteLength);
Я не понимаю, как работает механизм. Мне любопытно, почему он был представлен. Почему данные не разделяются между рабочими потоками, как в традиционной модели потоков, которая позволяет нескольким потокам обращаться к тем же
область памяти?
Другие фразы того же вопроса для разъяснения:
Почему буфер перекачивается при передаче?/Какова причина этого механизма?/Почему это было введено? Почему не могут быть разделены области памяти между рабочими?
Я ищу ответ из достоверных и/или официальных источников.
[1] https://developer.mozilla.org/en/docs/Web/API/Worker/postMessage
Ответы
Ответ 1
В Web Workers были введены переносимые объекты, чтобы улучшить производительность и копировать объекты (особенно, когда мы говорим об объектах большого размера). Он может быть параллелен сравнению между передачей по значению и передачей по ссылке в общих языках программирования (например, C/С++).
Дальнейшее ограничение того, что переносимые объекты не могут использоваться в потоке рабочего потока, возможно, было добавлено, так что гарантируется, что между двумя разными потоками не будет условий гонки (чтобы облегчить работу разработчиков, которые не нужно заботиться об этом). Кроме того, тогда также будет необходимо, чтобы в Javascript было реализовано намного больше примитивов concurrency (таких как мьютексы и т.д.). По сути, использование "передачи" означает, что вы просто собираетесь передавать данные в другой поток, а не использовать их из двух потоков одновременно, поэтому мы можем сказать, что реализация имеет смысл.
В целом, Web Workers не были разработаны как модель с общей памятью, а как модель обмена сообщениями.
Для дальнейшего ознакомления с разницей производительности отметьте this. Вы также можете проверить этот, где обсуждается, почему модель разделяемой памяти не была принята для веб-работников в WebKit.
Ответ 2
Это очень простой многопоточный вопрос. Если массив был доступен как в основном потоке, так и в рабочем месте, тогда необходимо будет заблокировать блокировку мьютекса, чтобы условия гонки не появлялись при доступе к буфере. Кроме того, я думаю, что буферы Array обычно используются, когда вам нужна производительность, но наличие блокировки для чтения/записи данных из этого буфера сделает работу медленнее.
Я думаю, что это одна из причин, почему ресурс "перемещен" и не используется.
TL; DR: многопоточность
Ответ 3
В соответствии с WHATWG ML выбор должен был потокобезопасный, потому что
Вы не можете делиться данными между работниками. Нет никакого (и не может быть) никакого общего состояния между несколькими потоками выполнения JS.
(источник)
Кроме того,
Мы хотим создайте источник ArrayBuffer и любые ArrayBufferViews, нулевую длину после отправки их работнику или обратно в основной поток. От ping-ponging тот же ArrayBuffer взад и вперед вы можете избежать выделяя новое хранилище каждой итерации.
(источник)
К сожалению, я не нахожу дискуссию о спецификациях, странице, где он должен быть размещен, дает 404, я постараюсь найти копировать в другое место
Ответ 4
Причина - производительность. Переданные данные не копируются, право собственности на ArrayBuffer передается получателю.
Для общей памяти вы должны использовать SharedArrayBuffer
Ответ 5
Только для четких передач применяется как для выделенных, так и для общих работников, поскольку оба используют MessagePorts
[1] Выделенные рабочие используют объекты MessagePort за кулисами.
[2] Общение с общими сотрудниками осуществляется с явными объектами MessagePort
postMessage указывается для передачи или клонирования на основе выбора вызывающего абонента:
[3] port.postMessage(сообщение [, transfer]) Посылает сообщение через канал. Объекты, перечисленные в передаче, переносятся, а не просто клонированы, что означает, что они больше не могут использоваться на стороне отправки.
Однако это указывает только на то, что плакат хранит копию, обычно основанную на эффективности, а не на том, что какая-либо память является общей.
Когда дело доходит до " памяти", четко указано, что он не должен использоваться совместно, независимо от типа рабочего или данные передаются или клонируются:
[4] Когда пользовательский агент должен запустить рабочего для script с URL-адресом URL-адреса, объектом настроек объекта настроек среды, и URL-адрес URL должен выполнить следующие шаги:
Создайте отдельную среду параллельного выполнения (т.е. отдельный поток или процесс или эквивалентную конструкцию) и выполните остальные шаги в этом контексте.
Итак, теперь вопрос: почему? Почему должен агент пользователя создавать параллельную среду выполнения для всех и всех типов рабочих?
Безопасность? Нет. Эффективность? (так как когда js эффективен?), ни.
Причина заключается в том, чтобы иметь возможность соблюдать или, скорее, соблюдать всю спецификацию. Если вы выполните ссылку [4], вы заметите как минимум:
Когда пользовательский агент должен завершать работу, он должен выполнить следующие шаги параллельно с основным циклом работника (описанная выше модель обработки "рабочий рабочий" ):
1) Установите флаг закрытия рабочего объекта WorkerGlobalScope равным true.
2) Если в задачах очереди объектов объекта WorkerGlobalScope есть задачи, поставленные в очередь, отбросьте их без их обработки.
3) Отмените script, выполняемый в рабочем времени.
4) Если рабочий объект WorkerGlobalScope фактически является объектом DedicatedWorkerGlobalScope (т.е. рабочий является специальным работником), то пустая очередь сообщений порта, с которой запутанный порт работ запутан.
И это только одна часть спецификации.
Так почему же? Он сможет управлять совокупностью событий, происходящих в рабочем пространстве. Разработчики должны проводить параллелизацию рабочих или безуспешно.
:)
Ответ 6
Это заставляет зависеть от исторических обстоятельств, поскольку в спецификацию были добавлены переносы, после того как работники были представлены как API-интерфейс передачи сообщений [1] с намерением внести минимальные изменения [2] [3].
[1] https://bugzilla.mozilla.org/show_bug.cgi?id=720083 (Запрос на внедрение в Firefox)
[2] https://mail.mozilla.org/pipermail/es-discuss/2014-May/037239.html
Потому что, когда концепция Transferable была формализована в HTML5 spec, была цель внести минимально возможные изменения. Переносимым было в основном обобщение MessagePort, которое было единственный тип, который ранее мог быть "передан" веб-работнику. Стерилизация - это только понятие в тексте спецификации, а не в IDL. Переносимый typedef не имеет связанных методов. Единственный путь к средству объект должен передать его веб-работнику. Были просит предоставить метод "close()" и сделать Transferable a суб-интерфейс нового интерфейса Closable. Мы сопротивлялись изменения, поскольку они по существу обеспечили бы ручную память управление JavaScript.
[3] https://mail.mozilla.org/pipermail/es-discuss/2014-May/037227.html
Во-первых, некоторый фон. Когда были созданы типизированные массивы, они были указанным в Web IDL и его привязке к ECMAScript. Были попытки во время создания типизированных массивов, чтобы генерировать исключения на некоторых операции - как индексирование вне диапазона - но один за другим это были обнаружил, что он несовместим ни с веб-IDL, ни с ECMAScript семантика, как поиск свойств.
Ответ 7
Для использования этих понятий в javascript вы должны использовать эти кодировки,
PostMesage(aMessage, transferList)
В списке TransferList вы должны указать передаваемые объекты, которые содержатся в файле:
var objData =
{
str: "string",
ab: new ArrayBuffer(100),
i8: new Int8Array(200)
};
objWorker.postMessage(objData, [objData.ab, objData.i8.buffer]);
On other side:
self.onmessage = function(objEvent)
{
var strText = objEvent.data.str;
var objTypedArray = objEvent.data.ab;
var objTypedArrayView = objEvent.data.i8;
}
Чтобы использовать "переносимые объекты", вы фактически передаете право собственности на объект на веб-пользователя или у него. Это как передача по ссылке, где копия не сделана. Разница между ним и обычной передачей по ссылке заключается в том, что сторона, которая передала данные, больше не может ее получить.