2016-07-03 11 views
18

Javascript consente il trasferimento dei buffer da un thread di origine a un thread di lavoro. Altrimenti, ArrayBuffer viene copiato, quindi passato al lavoratore. buffer trasferiti non sono accessibili ("castrati") in [1] il filo fonte:perché i buffer trasferiti sono sterilizzati in javascript?

// 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); 

I Unterstand come funziona il meccanismo. Sono comunque curioso del perché è stato presentato. Perché i dati condivisi tra thread di lavoro non sono condivisi, come in un modello di threading tradizionale, che consente a più thread di accedere alla stessa area di memoria ?


Altri fraseggi della stessa domanda di chiarimento:

Perché sono il Buffer castrati sul trasferimento?/Qual è il ragionamento dietro questo meccanismo?/Perché è stato introdotto? Perché le regioni di memoria non possono essere condivise tra i lavoratori?

Sto cercando una risposta da fonti credibili e/o ufficiali.


[1] https://developer.mozilla.org/en/docs/Web/API/Worker/postMessage

+1

Grazie, Michal Charemza. Ho aggiunto la tua frase alla domanda in quanto questo era il motivo della domanda. –

risposta

12

oggetti Valori sono stati introdotti nei lavoratori Web al fine di migliorare le prestazioni e la copia di oggetti (soprattutto quando si parla di oggetti di grandi dimensioni). Può essere parallelizzato a un confronto tra pass-by-value e pass-by-reference in linguaggi di programmazione comuni (come C/C++).

L'ulteriore restrizione, che gli oggetti trasferibili non possono essere utilizzati nel thread del worker di origine, è stata probabilmente aggiunta, in modo che sia garantito che non ci saranno condizioni di gara tra i 2 diversi thread (per facilitare il lavoro degli sviluppatori che non devono preoccuparsene). Inoltre, ci sarebbe anche bisogno di molte più primitive di concorrenza da implementare in Javascript (come mutex, ecc.). In sostanza, l'uso di "trasferimento" significa che hai intenzione di trasferire i dati su un altro thread, non usarli da 2 thread contemporaneamente, quindi potremmo dire che l'implementazione ha senso.

In generale, i Web Worker non sono stati progettati come un modello di memoria condivisa, ma come un modello di scambio di messaggi.

Per ulteriori informazioni sulla differenza di prestazioni, verificare this. Puoi anche controllare this, dove c'è una discussione sul perché il modello di memoria condivisa non è stato adottato per i Web Worker in WebKit.

+0

https://www.w3.org/TR/html5/infrastructure.html#transferable-objects – Knu

+1

+1 per "In generale, i Web Worker non sono stati progettati come un modello di memoria condivisa, ma come un modello di scambio di messaggi ". Citation from the last link: "È un principio di progettazione primario dei web worker che la complessità di fare il corretto design multithread non sarà esposta agli sviluppatori JavaScript". –

2

Il motivo è la prestazione. I dati inviati non vengono copiati, la proprietà di ArrayBuffer viene trasferita al destinatario.

Per la memoria condivisa, è necessario utilizzare SharedArrayBuffer

7

Questa è una domanda multi-threading molto di base. Se la matrice era accessibile sia nel thread principale che nel worker, allora sarebbe necessario implementare un blocco mutex in modo che le condizioni di gara non vengano visualizzate quando si accede al buffer. Inoltre, penso che i buffer di Array vengano solitamente usati quando si vuole ottenere prestazioni, ma avere un blocco per leggere/scrivere dati da quel buffer renderebbe l'operatore più lento.

Immagino che questo sia uno dei motivi per cui la risorsa viene "spostata" e non condivisa.

TL; DR: multi-threading

3

conseguenza alla WHATWG ML, la scelta doveva essere thread safe, perché

Non è possibile condividere i dati tra i lavoratori. Non esiste (e non può esserci) uno stato condiviso tra più thread di esecuzione JS.

(source)

Inoltre,

Vogliamo rendere la fonte ArrayBuffer, e qualsiasi ArrayBufferViews, lunghezza zero su di loro la pubblicazione di un lavoratore o di nuovo al thread principale. Con ping-ponging lo stesso ArrayBuffer avanti e indietro è possibile evitare allocando nuovo backing store ogni iterazione.

(source)

Purtroppo, non trovo la discussione su specifiche, the page dove dovrebbe essere ospitato dà 404, cercherò di trovare una copia da qualche altra parte

0

E cuciture essere motivati ​​dalle circostanze storiche, in quanto i valori trasferibili sono stati aggiunti alla specifica dopo che i lavoratori sono stati introdotti come API di passaggio dei messaggi [1] con l'intenzione di apportare modifiche minime [2] [3].


[1] https://bugzilla.mozilla.org/show_bug.cgi?id=720083 (Richiesta di implementazione in Firefox)

[2] https://mail.mozilla.org/pipermail/es-discuss/2014-May/037239.html

Perché quando il concetto di valori è stato formalizzato nel HTML5 spec, c'era un obiettivo per apportare le modifiche minime possibili. Trasferibile era fondamentalmente una generalizzazione di MessagePort, che era l'unico tipo che in precedenza poteva essere "trasferito" a un web worker. La neutralizzazione è solo un concetto in testo spec e non in IDL. Il typedef trasferibile non ha alcun metodo associato. L'unico modo in cui lo per neutralizzare un oggetto è di trasferirlo a un web worker. Sono state richieste per fornire un metodo "close()" e rendere trasferibile un'interfaccia secondaria di una nuova interfaccia Closable. Abbiamo resistito alla modifica di quelle perché avrebbero essenzialmente introdotto la gestione manuale della memoria in JavaScript.

[3] https://mail.mozilla.org/pipermail/es-discuss/2014-May/037227.html

In primo luogo, alcuni retroscena. Quando gli array digitati sono stati progettati, erano specificati con Web IDL e il relativo binding ECMAScript. Ci sono stati tentativi durante lo sviluppo di array digitati per generare eccezioni su alcune operazioni - come indicizzazione fuori intervallo - ma uno per uno erano scoperti come incompatibili con la semantica di Web ID o ECMAScript come la ricerca di proprietà.

+0

Questa non è affatto una ragione. Avere risorse condivise richiederebbe un lock dell'interprete globale, che vanificherebbe lo scopo di avere lavoratori in primo luogo, o avere oggetti di sincronizzazione, che sarebbero piuttosto alieni in JS. – transistor09

+0

@ transistor09 Puoi spiegare perché questo non è un motivo? Introdurre una piccola patch in una struttura esistente invece di specificare e implementare un secondo sistema completamente diverso, ha molto senso per me. –

+0

Quello che stai citando è * non un motivo *; è il più piccolo * cambiamento risultante * delle specifiche per consentire di avere oggetti condivisi ma di proprietà di ** solo un ** contesto alla volta (per ragioni già citate). – transistor09

0

Per utilizzare questi concetti in javascript è necessario utilizzare questi codici,

PostMesage(aMessage, transferList) 

In transferList è necessario specificare gli oggetti trasferibili, che conteneva in aMessage:

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; 
} 

di usare "oggetti trasferibili "in realtà trasferisci la proprietà dell'oggetto al o dal web worker. È come passare per riferimento dove non viene fatta una copia. La differenza tra questo e il normale pass-by-reference è che il lato che ha trasferito i dati non può più accedervi.

1

Giusto per essere chiari trasferimenti vale per entrambi i lavoratori dedicati e condivisi da entrambe le MessagePorts uso

[1] lavoratori dedicati utilizzano oggetti MessagePort dietro le quinte.

[2] Comunicare con i lavoratori in comune è fatto con MessagePort esplicito oggetti

postMessage è specificato di trasferire o clone basato sul del chiamante scelta:

[3] port.postMessage (messaggio [, trasferimento]) Invia un messaggio attraverso il canale. Gli oggetti elencati nel trasferimento vengono trasferiti, non solo clonati, il che significa che non sono più utilizzabili sul lato mittente.

Ciò tuttavia indica solo se il poster conserva una copia, in genere basata sull'efficienza e non se la memoria è condivisa.

Quando si tratta di "memoria" è chiaramente precisato che non deve essere condivisa indipendentemente dal tipo lavoratore o castrato dati sono trasferiti o clonato:

[4] Quando un agente utente è di eseguire un lavoratore per uno script con url URL, un impostazioni dell'ambiente oggetto impostazioni oggetto, e un URL di riferimento che deve eseguire le seguenti operazioni:

Creare un par separata ambiente di esecuzione allel (es. una filettatura separata o processo o costrutto equivalente) ed eseguire il resto di questi passaggi in tale contesto.

Quindi ora la domanda: perché? Perché deve l'agente utente crea un ambiente di esecuzione parallelo per tutti i tipi di lavoratori?

Sicurezza? No. Efficienza? (da quando è js efficiente?), neanche.

Il motivo è essere in grado di rispettare o piuttosto rispettare l'intera specifica.Se si segue la link [4] noterete al minimo:

Quando un agente utente è di terminare un lavoratore deve eseguire le seguenti operazioni in parallelo con ciclo principale del lavoratore (il "eseguire un lavoratore" modello di elaborazione definito sopra):

1) Impostare il flag di chiusura dell'oggetto WorkerGlobalScope su true.

2) Se sono presenti attività in coda nelle code delle attività del ciclo di eventi dell'oggetto WorkerGlobalScope, eliminarle senza elaborarle.

3) Interrompere lo script attualmente in esecuzione nel worker.

4) Se l'oggetto WorkerGlobalScope del worker è in realtà un oggetto DedicatedWorkerGlobalScope (ad esempio, il worker è un worker dedicato), quindi svuota la coda dei messaggi della porta della porta implicita del worker.

E questa è solo una parte delle specifiche.

Quindi, ancora perché? Deve essere in grado di gestire la totalità degli eventi che si svolgono nello spazio di lavoro. Gli attuatori devono parallelizzare i lavoratori o andare completamente fuori di testa. :)

Problemi correlati