Domanda

C'è un modo per eseguire il multithreading in JavaScript?

È stato utile?

Soluzione

Vedere http://caniuse.com/#search=worker per le informazioni di supporto più aggiornate.

Quello che segue è lo stato del supporto intorno al 2009.


Le parole che vuoi cercare su Google sono Thread di lavoro JavaScript

A parte Ingranaggi non c'è nulla di disponibile al momento, ma si parla molto di come implementarlo, quindi immagino che guardi questa domanda poiché la risposta cambierà senza dubbio in futuro.

Ecco la documentazione pertinente per Gears: API WorkerPool

WHATWG ha una bozza di raccomandazione per i thread di lavoro: Lavoratori del Web

E c'è anche quello di Mozilla Thread di lavoro DOM


Aggiornamento: Giugno 2009, stato attuale del supporto del browser per i thread JavaScript

Firefox 3.5 ha lavoratori web.Alcune demo dei web work, se vuoi vederli in azione:

Il plugin Gears può essere installato anche in Firefox.

Safari 4, e il Notturne WebKit avere thread di lavoro:

Cromo ha Gears integrato, quindi può eseguire thread, sebbene richieda una richiesta di conferma da parte dell'utente (e utilizzi un'API diversa per i lavoratori web, sebbene funzionerà in qualsiasi browser con il plug-in Gears installato):

  • Demo della piscina Worker di Google Gears (non è un buon esempio in quanto funziona troppo velocemente per essere testato in Chrome e Firefox, anche se IE lo esegue abbastanza lentamente da vederlo bloccare l'interazione)

IE8 E IE9 può eseguire discussioni solo con il plugin Gears installato

Altri suggerimenti

Modo diverso di eseguire il multi-threading e l'asincrono in JavaScript

Prima di HTML5 JavaScript consentiva solo l'esecuzione di un thread per pagina.

C'era un modo complicato per simulare un'esecuzione asincrona Prodotto, setTimeout(), setInterval(), XMLHttpRequest O gestori di eventi (vedi la fine di questo post per un esempio con prodotto E setTimeout()).

Ma con HTML5 ora possiamo utilizzare i thread di lavoro per parallelizzare l'esecuzione delle funzioni.Ecco un esempio di utilizzo.


Vero multithreading

Multithreading:Thread di lavoro JavaScript

HTML5 introdotto i thread dei Web Worker (vedi: compatibilità dei browser)
Nota:IE9 e le versioni precedenti non lo supportano.

Questi thread di lavoro sono thread JavaScript eseguiti in background senza influire sulle prestazioni della pagina.Per ulteriori informazioni su Lavoratore Web leggere la documentazione O questo tutorial.

Ecco un semplice esempio con 3 thread di lavoro Web che contano fino a MAX_VALUE e mostrano il valore calcolato corrente nella nostra pagina:

//As a worker normally take another JavaScript file to execute we convert the function in an URL: http://stackoverflow.com/a/16799132/2576706
function getScriptPath(foo){ return window.URL.createObjectURL(new Blob([foo.toString().match(/^\s*function\s*\(\s*\)\s*\{(([\s\S](?!\}$))*[\s\S])/)[1]],{type:'text/javascript'})); }

var MAX_VALUE = 10000;

/*
 *	Here are the workers
 */
//Worker 1
var worker1 = new Worker(getScriptPath(function(){
    self.addEventListener('message', function(e) {
        var value = 0;
        while(value <= e.data){
            self.postMessage(value);
            value++;
        }
    }, false);
}));
//We add a listener to the worker to get the response and show it in the page
worker1.addEventListener('message', function(e) {
  document.getElementById("result1").innerHTML = e.data;
}, false);


//Worker 2
var worker2 = new Worker(getScriptPath(function(){
    self.addEventListener('message', function(e) {
        var value = 0;
        while(value <= e.data){
            self.postMessage(value);
            value++;
        }
    }, false);
}));
worker2.addEventListener('message', function(e) {
  document.getElementById("result2").innerHTML = e.data;
}, false);


//Worker 3
var worker3 = new Worker(getScriptPath(function(){
    self.addEventListener('message', function(e) {
        var value = 0;
        while(value <= e.data){
            self.postMessage(value);
            value++;
        }
    }, false);
}));
worker3.addEventListener('message', function(e) {
    document.getElementById("result3").innerHTML = e.data;
}, false);


// Start and send data to our worker.
worker1.postMessage(MAX_VALUE); 
worker2.postMessage(MAX_VALUE); 
worker3.postMessage(MAX_VALUE);
<div id="result1"></div>
<div id="result2"></div>
<div id="result3"></div>

Possiamo vedere che i tre thread vengono eseguiti in concorrenza e stampano il loro valore corrente nella pagina.Non bloccano la pagina perché vengono eseguiti in background con thread separati.


Multithreading:con più iframe

Un altro modo per raggiungere questo obiettivo è utilizzare più iframe, ognuno eseguirà un thread.Possiamo dare il iFrame alcuni parametri tramite l'URL e il iFrame può comunicare con i suoi genitori per ottenere il risultato e stamparlo (il iFrame deve essere nello stesso dominio).

Questo esempio non funziona in tutti i browser! iframe di solito viene eseguito nello stesso thread/processo della pagina principale (ma Firefox e Chromium sembrano gestirlo diversamente).

Poiché lo snippet di codice non supporta più file HTML, fornirò semplicemente i diversi codici qui:

indice.html:

//The 3 iframes containing the code (take the thread id in param)
<iframe id="threadFrame1" src="thread.html?id=1"></iframe>
<iframe id="threadFrame2" src="thread.html?id=2"></iframe>
<iframe id="threadFrame3" src="thread.html?id=3"></iframe>

//Divs that shows the result
<div id="result1"></div>
<div id="result2"></div>
<div id="result3"></div>


<script>
    //This function is called by each iframe
    function threadResult(threadId, result) {
        document.getElementById("result" + threadId).innerHTML = result;
    }
</script>

discussione.html:

//Get the parameters in the URL: http://stackoverflow.com/a/1099670/2576706
function getQueryParams(paramName) {
    var qs = document.location.search.split('+').join(' ');
    var params = {}, tokens, re = /[?&]?([^=]+)=([^&]*)/g;
    while (tokens = re.exec(qs)) {
        params[decodeURIComponent(tokens[1])] = decodeURIComponent(tokens[2]);
    }
    return params[paramName];
}

//The thread code (get the id from the URL, we can pass other parameters as needed)
var MAX_VALUE = 100000;
(function thread() {
    var threadId = getQueryParams('id');
    for(var i=0; i<MAX_VALUE; i++){
        parent.threadResult(threadId, i);
    }
})();

Simula il multi-threading

Filo singolo:emula la concorrenza JavaScript con setTimeout()

Il modo "ingenuo" sarebbe eseguire la funzione setTimeout() uno dopo l'altro in questo modo:

setTimeout(function(){ /* Some tasks */ }, 0);
setTimeout(function(){ /* Some tasks */ }, 0);
[...]

Ma questo metodo non funziona perché ogni attività verrà eseguita una dopo l'altra.

Possiamo simulare l'esecuzione asincrona chiamando la funzione ricorsivamente in questo modo:

var MAX_VALUE = 10000;

function thread1(value, maxValue){
    var me = this;
    document.getElementById("result1").innerHTML = value;
    value++;
  
    //Continue execution
    if(value<=maxValue)
        setTimeout(function () { me.thread1(value, maxValue); }, 0);
}

function thread2(value, maxValue){
    var me = this;
    document.getElementById("result2").innerHTML = value;
    value++;
	
    if(value<=maxValue)
        setTimeout(function () { me.thread2(value, maxValue); }, 0);
}

function thread3(value, maxValue){
    var me = this;
    document.getElementById("result3").innerHTML = value;
    value++;
	
    if(value<=maxValue)
        setTimeout(function () { me.thread3(value, maxValue); }, 0);
}

thread1(0, MAX_VALUE);
thread2(0, MAX_VALUE);
thread3(0, MAX_VALUE);
<div id="result1"></div>
<div id="result2"></div>
<div id="result3"></div>

Come puoi vedere questo secondo metodo è molto lento e blocca il browser perché utilizza il thread principale per eseguire le funzioni.


Filo singolo:emula la concorrenza JavaScript con yield

Prodotto è una nuova funzionalità in ECMAScript 6, funziona solo sulle versioni più vecchie di Firefox e Chrome (in Chrome è necessario abilitare JavaScript sperimentale apparendo in chrome://flags/#enable-javascript-harmony).

La parola chiave yield mette in pausa l'esecuzione della funzione del generatore e il valore dell'espressione che segue la parola chiave yield viene restituito al chiamante del generatore.Può essere pensato come una versione basata su generatore della parola chiave return.

Un generatore consente di sospendere l'esecuzione di una funzione e riprenderla in seguito.Un generatore può essere utilizzato per programmare le tue funzioni con una tecnica chiamata trampolino.

Ecco l'esempio:

var MAX_VALUE = 10000;

Scheduler = {
	_tasks: [],
	add: function(func){
		this._tasks.push(func);
	},	
	start: function(){
		var tasks = this._tasks;
		var length = tasks.length;
		while(length>0){
			for(var i=0; i<length; i++){
				var res = tasks[i].next();
				if(res.done){
					tasks.splice(i, 1);
					length--;
					i--;
				}
			}
		}
	}	
}


function* updateUI(threadID, maxValue) {
  var value = 0;
  while(value<=maxValue){
	yield document.getElementById("result" + threadID).innerHTML = value;
	value++;
  }
}

Scheduler.add(updateUI(1, MAX_VALUE));
Scheduler.add(updateUI(2, MAX_VALUE));
Scheduler.add(updateUI(3, MAX_VALUE));

Scheduler.start()
<div id="result1"></div>
<div id="result2"></div>
<div id="result3"></div>

Con le "specifiche secondarie" di HTML5 non è più necessario hackerare Javascript con setTimeout(), setInterval(), ecc.

HTML5 & Friends introduce javascript Lavoratori del Web specifica.È un'API per l'esecuzione di script in modo asincrono e indipendente.

Collegamenti a specifica e un tutorial.

Non esiste un vero threading in JavaScript.Essendo JavaScript il linguaggio malleabile che è, ti consente di emularne una parte.Ecco un esempio Mi sono imbattuto l'altro giorno.

Non esiste un vero multi-threading in Javascript, ma puoi ottenere un comportamento asincrono utilizzando setTimeout() e richieste AJAX asincrone.

Cosa stai cercando di realizzare esattamente?

Ecco solo un modo per farlo simulare multithreading in Javascript

Ora creerò 3 thread che calcoleranno l'addizione dei numeri, i numeri possono essere divisi con 13 e i numeri possono essere divisi con 3 fino a 10000000000.E queste 3 funzioni non sono in grado di essere eseguite contemporaneamente a ciò che significa Concorrenza.Ma ti mostrerò un trucco che farà sì che queste funzioni vengano eseguite in modo ricorsivo nello stesso tempo: jsFiddle

Questo codice appartiene a me.

Parte del corpo

    <div class="div1">
    <input type="button" value="start/stop" onclick="_thread1.control ? _thread1.stop() : _thread1.start();" /><span>Counting summation of numbers till 10000000000</span> = <span id="1">0</span>
</div>
<div class="div2">
    <input type="button" value="start/stop" onclick="_thread2.control ? _thread2.stop() : _thread2.start();" /><span>Counting numbers can be divided with 13 till 10000000000</span> = <span id="2">0</span>
</div>
<div class="div3">
    <input type="button" value="start/stop" onclick="_thread3.control ? _thread3.stop() : _thread3.start();" /><span>Counting numbers can be divided with 3 till 10000000000</span> = <span id="3">0</span>
</div>

Parte Javascript

var _thread1 = {//This is my thread as object
    control: false,//this is my control that will be used for start stop
    value: 0, //stores my result
    current: 0, //stores current number
    func: function () {   //this is my func that will run
        if (this.control) {      // checking for control to run
            if (this.current < 10000000000) {
                this.value += this.current;   
                document.getElementById("1").innerHTML = this.value;
                this.current++;
            }
        }
        setTimeout(function () {  // And here is the trick! setTimeout is a king that will help us simulate threading in javascript
            _thread1.func();    //You cannot use this.func() just try to call with your object name
        }, 0);
    },
    start: function () {
        this.control = true;   //start function
    },
    stop: function () {
        this.control = false;    //stop function
    },
    init: function () {
        setTimeout(function () {
            _thread1.func();    // the first call of our thread
        }, 0)
    }
};
var _thread2 = {
    control: false,
    value: 0,
    current: 0,
    func: function () {
        if (this.control) {
            if (this.current % 13 == 0) {
                this.value++;
            }
            this.current++;
            document.getElementById("2").innerHTML = this.value;
        }
        setTimeout(function () {
            _thread2.func();
        }, 0);
    },
    start: function () {
        this.control = true;
    },
    stop: function () {
        this.control = false;
    },
    init: function () {
        setTimeout(function () {
            _thread2.func();
        }, 0)
    }
};
var _thread3 = {
    control: false,
    value: 0,
    current: 0,
    func: function () {
        if (this.control) {
            if (this.current % 3 == 0) {
                this.value++;
            }
            this.current++;
            document.getElementById("3").innerHTML = this.value;
        }
        setTimeout(function () {
            _thread3.func();
        }, 0);
    },
    start: function () {
        this.control = true;
    },
    stop: function () {
        this.control = false;
    },
    init: function () {
        setTimeout(function () {
            _thread3.func();
        }, 0)
    }
};

_thread1.init();
_thread2.init();
_thread3.init();

Spero che in questo modo possa essere utile.

Potresti usare JavaScript narrativo, un compilatore che trasformerà il tuo codice in una macchina a stati, permettendoti effettivamente di emulare il threading.Lo fa aggiungendo un operatore "cedente" (annotato come '->') al linguaggio che consente di scrivere codice asincrono in un singolo blocco di codice lineare.

Il nuovo motore V8 che dovrebbe uscire oggi lo supporta (credo)

Un altro metodo possibile è utilizzare un interprete javascript nell'ambiente javascript.

Creando più interpreti e controllandone l'esecuzione dal thread principale, puoi simulare il multi-threading con ciascun thread in esecuzione nel proprio ambiente.

L'approccio è in qualche modo simile ai web work, ma fornisci all'interprete l'accesso all'ambiente globale del browser.

Ho realizzato un piccolo progetto per dimostrarlo.

Una spiegazione più dettagliata in questo post del blog.

In Javascript non elaborato, la cosa migliore che puoi fare è utilizzare le poche chiamate asincrone (xmlhttprequest), ma non è realmente threading e molto limitato. Google Gears aggiunge una serie di API al browser, alcune delle quali possono essere utilizzate per il supporto del threading.

Se non puoi o non vuoi usare materiale AJAX, usa un iframe o dieci!;) Puoi avere processi in esecuzione in iframe in parallelo con la pagina master senza preoccuparti di problemi comparabili tra browser o problemi di sintassi con dot net AJAX ecc., e puoi chiamare il JavaScript della pagina master (incluso il JavaScript che ha importato) da un iFrame.

Ad esempio, in un iframe principale, per chiamare egFunction() nel documento principale una volta caricato il contenuto dell'iframe (questa è la parte asincrona)

parent.egFunction();

Genera dinamicamente anche gli iframe in modo che il codice html principale ne sia libero, se lo desideri.

Javascript non ha thread, ma abbiamo lavoratori.

I lavoratori possono essere una buona scelta se non hai bisogno di oggetti condivisi.

La maggior parte delle implementazioni dei browser distribuiranno effettivamente i lavoratori su tutti i core consentendoti di utilizzare tutti i core.Puoi vedere una demo di questo Qui.

Ho sviluppato una libreria chiamata task.js questo lo rende molto facile da fare.

task.js Interfaccia semplificata per far sì che il codice ad uso intensivo della CPU venga eseguito su tutti i core (node.js e web)

Un esempio potrebbe essere

function blocking (exampleArgument) {
    // block thread
}

// turn blocking pure function into a worker task
const blockingAsync = task.wrap(blocking);

// run task on a autoscaling worker pool
blockingAsync('exampleArgumentValue').then(result => {
    // do something with result
});

Con HTML5 specifica non è necessario scrivere troppo JS per lo stesso o trovare alcuni hack.

Una delle funzionalità introdotte in HTML5 è Lavoratori del Web che è JavaScript in esecuzione in background, indipendentemente da altri script, senza influire sulle prestazioni della pagina.

È supportato in quasi tutti i browser:

Cromo - 4.0+

IE-10.0+

Mozilla-3.5+

Safari - 4.0+

Opera - 11.5+

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top