Question

Est-il possible de faire du multi-threading dans le JavaScript?

Était-ce utile?

La solution

Voir http://caniuse.com/#search=worker pour les plus up-to-date de l'appui d'infos.

La suite est à l'état de soutenir circa 2009.


Les mots que vous voulez de google sont JavaScript Threads De Travail

En dehors de partir Engrenages il n'y a rien de disponible dès maintenant, mais il ya beaucoup de parler de la façon de mettre en œuvre ce donc je suppose que regarder à cette question que la réponse sera sans aucun doute changer dans le futur.

Voici la documentation pertinente pour Engrenages: WorkerPool API

WHATWG a un Projet de Recommandation pour les threads de travail: Des Web Workers

Et il y a aussi de Mozilla DOM Threads de travail


Mise à jour: En juin 2009, l'état actuel de navigateur prenant en charge JavaScript fils

Firefox 3.5 a des web workers.Quelques démos de des web workers, si vous voulez les voir en action:

Les Engrenages plugin peut aussi être installé dans Firefox.

Safari 4, et la WebKit nightlies ont de threads de travail:

Chrome Gears cuit, donc il peut faire des threads, même si elle nécessite une confirmation de l'utilisateur (et il utilise une API différente de web les travailleurs, bien que cela fonctionnera dans n'importe quel navigateur avec les Engrenages plugin installé):

  • Google Gears WorkerPool Démo (pas un bon exemple car il va trop vite pour tester sur Chrome et Firefox, bien que IE fonctionne il suffisamment lente pour voir le blocage de l'interaction)

IE8 et IE9 ne peut que faire des discussions avec les Engrenages plugin installé

Autres conseils

Façon différente de faire du multi-threading et Asynchrone en JavaScript

Avant de HTML5 JavaScript seulement permis à l'exécution d'un thread par page.

Il y a quelques hacky manière à simuler une exécution asynchrone avec Rendement, setTimeout(), setInterval(), XMLHttpRequest ou les gestionnaires d'événements (voir à la fin de ce post pour un exemple avec rendement et setTimeout()).

Mais avec HTML5 on peut maintenant utiliser des Threads de travail pour paralléliser l'exécution de fonctions.Voici un exemple d'utilisation.


Véritable multi-threading

Le Multi-threading:JavaScript Threads De Travail

HTML5 introduit Web de Threads de travail (voir: compatibilités navigateurs)
Note:IE9 et les versions antérieures ne prennent pas en charge.

Ces threads sont JavaScript threads qui s'exécutent en arrière-plan sans affecter les performances de la page.Pour plus d'informations sur Web Travailleur lire la documentation ou ce tutoriel.

Voici un exemple simple avec 3 Web Worker threads qui comptent pour MAX_VALUE et affichage de la valeur calculée dans notre page:

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

Nous pouvons voir que les trois fils sont exécutées dans la simultanéité et de imprimer leur valeur actuelle en de la page.Ils ne gèlent pas la page, car ils sont exécutés en arrière-plan avec des threads séparés.


Le Multi-threading:avec plusieurs iframes

Une autre façon d'y parvenir est d'utiliser plusieurs iframes, avec , dans chacune d'exécuter un thread.Nous pouvons donner l' iframe certains paramètres de l'URL et de la iframe peut communiquer avec son parent pour obtenir le résultat et l'imprimer en arrière (l' iframe doit être dans le même domaine).

Cet exemple ne fonctionne pas dans tous les navigateurs! iframes généralement exécuté dans le même thread/processus de la page principale (mais Firefox et Chrome semblent gérer la situation différemment).

Depuis l'extrait de code ne prend pas en charge plusieurs fichiers HTML, je vais fournir les différents codes ici:

index.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>

thread.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);
    }
})();

Simuler le multi-threading

Single-thread:émuler JavaScript simultanéité avec setTimeout()

La "naïve" serait d'exécuter la fonction setTimeout() l'un après l'autre comme ceci:

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

Mais cette méthode ne fonctionne pas parce que chaque tâche seront exécutées l'une après l'autre.

Nous pouvons simuler l'exécution asynchrone par l'appel de la fonction de manière récursive comme ceci:

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>

Comme vous pouvez le voir, cette seconde méthode est très lent et bloque le navigateur, car il utilise le thread principal pour exécuter les fonctions.


Single-thread:émuler JavaScript simultanéité avec le rendement

Rendement est une nouvelle fonctionnalité dans ECMAScript 6, il ne fonctionne que sur l'ancienne version de Firefox et de Chrome (dans Chrome, vous devez activer Expérimentale JavaScript apparaissant dans chrome://flags/#enable-javascript-harmonie).

Le mot clé yield causes générateur de fonction interrompre l'exécution et la valeur de l'expression qui suit le mot clé yield est renvoyée vers le générateur de l'appelant.Il peut être considéré comme un générateur de version de base du mot-clé return.

Un générateur vous permet de suspendre l'exécution d'une fonction et de le reprendre plus tard.Un générateur peut être utilisé pour programmer vos fonctions à l'aide d'une technique appelée le trampoline.

Voici l'exemple:

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>

Avec le HTML5 "côté-specs" pas besoin de bidouille javascript plus avec setTimeout(), fonction setInterval(), etc.

HTML5 et ses Amis introduit le javascript Des Web Workers spécification.C'est une API pour l'exécution de scripts en mode asynchrone et de façon indépendante.

Des liens vers les spécification et un tutoriel.

Il n'y a pas de véritable filetage en JavaScript.JavaScript étant malléables que la langue qu'il est, ne vous permet pas d'émuler certaines d'entre elles.Voici un exemple Je suis tombé l'autre jour.

Il n'y a pas de vrai multi-threading en Javascript, mais vous pouvez obtenir un comportement asynchrone à l'aide de setTimeout() et asynchrone des requêtes AJAX.

Qu'est-ce exactement que vous voulez accomplir?

C'est juste une façon de simuler le multi-threading en Javascript

Maintenant, je vais créer 3 fils qui va calculer les nombres outre, les numéros peuvent être divisés avec 13, et les chiffres peuvent être divisés par 3 jusqu'à 10000000000.Et ces 3 fonctions ne sont pas en mesure d'exécuter en même temps que ce que la Simultanéité des moyens.Mais je vais vous montrer une astuce qui fera de ces fonctions de s'exécuter de façon récursive dans le même temps : jsFiddle

Ce code m'appartient.

Partie Du Corps

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

Partie 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();

J'espère que de cette façon, vous sera utile.

Vous pouvez utiliser Récit JavaScript, un compilateur qui transforme votre code dans une machine d'état, de manière efficace vous permettant d'émuler le filetage.Il le fait par l'ajout d'un "rendement" de l'opérateur (notées comme des '->') pour le langage qui permet d'écrire du code asynchrone dans un seul, linéaire bloc de code.

Le nouveau moteur v8 qui devrait sortir aujourd'hui le supporte (je pense)

Une autre méthode possible est d'utiliser un interpréteur javascript dans le code javascript de l'environnement.

Par la création de plusieurs interprètes et de contrôle de leur exécution dans le thread principal, vous pouvez simuler le multi-threading avec chaque thread exécute dans son propre environnement.

L'approche est quelque peu semblable à des web workers, mais vous donnez l'interprète de l'accès au navigateur de l'environnement mondial.

J'ai fait un petit projet à preuve de cette.

Une explication plus détaillée dans ce blog.

En raw, le Javascript, le meilleur que vous pouvez faire est en utilisant les quelques appels asynchrones (xmlhttprequest), mais ce n'est pas vraiment le filetage et le très limitée. Google Gears ajoute un certain nombre d'Api pour le navigateur, certaines peuvent être utilisés pour l'enfilage de soutien.

Si vous ne pouvez pas ou ne voulez pas utiliser de l'AJAX trucs, utiliser une iframe ou dix!;) Vous pouvez avoir des processus en cours d'exécution dans des iframes, en parallèle avec la page principale sans se soucier de la croix-navigateur comparable questions ou des questions de syntaxe avec dot net, AJAX, etc, et vous pouvez appeler la page principale du JavaScript (y compris le code JavaScript qu'il a importés) à partir d'une iframe.

E. g, chez un parent, un iframe, à l'appel egFunction() dans le document parent une fois le contenu de l'iframe est chargé (c'est la partie asynchrone)

parent.egFunction();

Générer dynamiquement le iframes trop de sorte que le principal code html est libre de partir si vous le souhaitez.

Javascript n'a pas de fils, mais nous avons des travailleurs.

Les travailleurs peuvent être un bon choix si vous n'avez pas besoin d'objets partagés.

La plupart des navigateurs implémentations fait de propager des travailleurs dans tous les cœurs vous permettant d'utiliser tous les cœurs.Vous pouvez voir une démo de ce ici.

J'ai développé une bibliothèque appelée task.js qui fait cela très facile à faire.

task.js Interface simplifiée pour l'obtention de l'UC de code à exécuter sur tous les cœurs (node.js et web)

Un exemple serait

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

Avec HTML5 spécification vous ne devez pas écrire trop de JS pour le même ou trouver des hacks.

Une des fonctionnalité introduite dans HTML5 Des Web Workers qui est le code JavaScript s'exécutant en arrière-plan,indépendamment des autres scripts, sans affecter les performances de la page.

Il est soutenu dans presque tous les navigateurs :

Chrome 4.0+

IE - 10.0+

Mozilla - 3.5+

Safari 4.0+

Opéra - 11.5+

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top