क्या जावास्क्रिप्ट में मल्टी-थ्रेडिंग करने का कोई तरीका है?
क्या जावास्क्रिप्ट में मल्टी-थ्रेडिंग करने का कोई तरीका है?
जवाबों:
सबसे अद्यतित समर्थन जानकारी के लिए http://caniuse.com/#search=worker देखें ।
निम्नलिखित समर्थन 2009 की स्थिति थी।
जिन शब्दों को आप Google के लिए चाहते हैं, वे जावास्क्रिप्ट वर्कर थ्रेड हैं
गियर्स के अलावा अभी कुछ भी उपलब्ध नहीं है, लेकिन इसे लागू करने के तरीके के बारे में बहुत सारी बातें हैं, इसलिए मुझे लगता है कि इस प्रश्न को देखें क्योंकि उत्तर भविष्य में कोई संदेह नहीं होगा।
यहां गियर्स के लिए प्रासंगिक प्रलेखन है: वर्करपूल एपीआई
WHATWG के पास वर्कर थ्रेड्स के लिए ड्राफ्ट की सिफारिश है: वेब वर्कर्स
और इसमें मोज़िला का DOM वर्कर थ्रेड भी है
अपडेट: जून 2009, जावास्क्रिप्ट धागे के लिए ब्राउज़र समर्थन की वर्तमान स्थिति
फ़ायरफ़ॉक्स 3.5 में वेब कर्मचारी हैं। वेब कर्मचारियों के कुछ डेमो, यदि आप उन्हें कार्रवाई में देखना चाहते हैं:
गियर्स प्लगइन को फ़ायरफ़ॉक्स में भी स्थापित किया जा सकता है।
सफ़ारी 4 , और वेबकीट नाइटलाइफ़ में श्रमिक सूत्र हैं:
Chrome में गियर्स बेक किया गया है, इसलिए यह थ्रेड्स कर सकता है, हालांकि इसके लिए उपयोगकर्ता से पुष्टिकरण प्रॉम्प्ट की आवश्यकता होती है (और यह वेब वर्कर्स के लिए एक अलग API का उपयोग करता है, हालांकि यह Gears प्लगइन के साथ किसी भी ब्राउज़र में काम करेगा):
IE8 और IE9 केवल थ्रेड्स गियर्स प्लगइन के साथ कर सकते हैं
एचटीएमएल 5 जावास्क्रिप्ट से पहले केवल प्रति पृष्ठ एक धागे के निष्पादन की अनुमति दी गई थी।
कुछ hacky तरीके के साथ एक अतुल्यकालिक निष्पादन अनुकरण करने के लिए हुई थी यील्ड , setTimeout(), setInterval(), XMLHttpRequestया ईवेंट हैंडलर्स (इस पोस्ट के अंत के साथ एक उदाहरण के लिए देखें उपज औरsetTimeout() )।
लेकिन HTML5 के साथ अब हम फ़ंक्शन के निष्पादन को समानांतर करने के लिए वर्कर थ्रेड्स का उपयोग कर सकते हैं। यहाँ उपयोग का एक उदाहरण है।
HTML5 ने वेब वर्कर थ्रेड्स देखें (देखें: ब्राउज़र कॉम्पिटिशन )
नोट: IE9 और पुराने संस्करण इसका समर्थन नहीं करते हैं।
ये वर्कर थ्रेड जावास्क्रिप्ट थ्रेड होते हैं जो पृष्ठ के प्रदर्शन को प्रभावित किए बिना पृष्ठभूमि में चलते हैं। वेब वर्कर के बारे में अधिक जानकारी के लिए प्रलेखन या इस ट्यूटोरियल को पढ़ें ।
यहां 3 वेब वर्कर थ्रेड्स के साथ एक सरल उदाहरण दिया गया है जो MAX_VALUE पर गिना जाता है और हमारे पृष्ठ में वर्तमान गणना मूल्य दिखाता है:
//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>
हम यह देख सकते हैं कि तीन थ्रेड्स को समरूपता में निष्पादित किया जाता है और पृष्ठ में उनके वर्तमान मूल्य को प्रिंट करता है। वे पृष्ठ को फ्रीज नहीं करते क्योंकि वे अलग थ्रेड्स के साथ पृष्ठभूमि में निष्पादित होते हैं।
इसे प्राप्त करने का एक और तरीका है कई आइफ्रेम का उपयोग करना , प्रत्येक एक थ्रेड को निष्पादित करेगा। हम दे सकते हैं आइफ्रेम यूआरएल और से कुछ मानकों आइफ्रेम आदेश परिणाम प्राप्त है और इसे वापस प्रिंट करने के लिए अपने माता पिता के साथ संवाद कर सकते हैं ( आइफ्रेम उसी डोमेन में होना चाहिए)।
यह उदाहरण सभी ब्राउज़रों में काम नहीं करता है! iframes आमतौर पर मुख्य पृष्ठ के रूप में एक ही थ्रेड / प्रक्रिया में चलते हैं (लेकिन फ़ायरफ़ॉक्स और क्रोमियम इसे अलग तरह से संभालते हैं)।
चूंकि कोड स्निपेट एकाधिक HTML फ़ाइलों का समर्थन नहीं करता है, इसलिए मैं यहां विभिन्न कोड प्रदान करूंगा:
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);
}
})();
'भोले' तरीके से setTimeout()एक के बाद एक फंक्शन को अंजाम देना होगा:
setTimeout(function(){ /* Some tasks */ }, 0);
setTimeout(function(){ /* Some tasks */ }, 0);
[...]
लेकिन यह विधि काम नहीं करती है क्योंकि प्रत्येक कार्य को एक के बाद एक निष्पादित किया जाएगा।
हम पुनरावर्ती रूप से फ़ंक्शन को कॉल करके अतुल्यकालिक निष्पादन को अनुकरण कर सकते हैं:
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>
जैसा कि आप देख सकते हैं यह दूसरी विधि बहुत धीमी है और ब्राउज़र को जमा देता है क्योंकि यह फ़ंक्शन को निष्पादित करने के लिए मुख्य थ्रेड का उपयोग करता है।
यील्ड ईसीएमएस्क्रिप्ट 6 में एक नई विशेषता है, यह केवल फ़ायरफ़ॉक्स और क्रोम के सबसे पुराने संस्करण पर काम करता है (क्रोम में आपको क्रोम में दिखाई देने वाले प्रायोगिक जावास्क्रिप्ट को सक्षम करने की आवश्यकता है : // झंडे / # सक्षम-जावास्क्रिप्ट-सद्भाव )।
उपज कीवर्ड जनरेटर फ़ंक्शन को विराम देने का कारण बनता है और उपज कीवर्ड के बाद अभिव्यक्ति का मूल्य जनरेटर के कॉलर को वापस कर दिया जाता है। इसे रिटर्न कीवर्ड के एक जनरेटर-आधारित संस्करण के रूप में सोचा जा सकता है।
एक जनरेटर आपको किसी फ़ंक्शन के निष्पादन को निलंबित करने और बाद में इसे फिर से शुरू करने की अनुमति देता है। एक जनरेटर को आपके कार्यों को शेड्यूल करने के लिए इस्तेमाल किया जा सकता है जिसे तकनीक कहा जाता है ट्रम्पोलिनिंग ।
यहाँ उदाहरण है:
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>
HTML5 "साइड-स्पेक्स" के साथ अब सेटटाइमआउट (), सेटइंटरवल (), आदि के साथ जावास्क्रिप्ट को हैक करने की कोई आवश्यकता नहीं है ।
HTML5 और मित्र जावास्क्रिप्ट वेब वर्कर्स का परिचय देते हैं विनिर्देश । यह अतुल्यकालिक और स्वतंत्र रूप से स्क्रिप्ट चलाने के लिए एक एपीआई है।
विनिर्देश और एक ट्यूटोरियल के लिए लिंक ।
यहाँ अनुकरण करने का एक तरीका है जावास्क्रिप्ट में मल्टी-थ्रेडिंग
अब मैं 3 थ्रेड बनाने जा रहा हूं, जो संख्याओं की गणना करेगा, संख्याओं को 13 से विभाजित किया जा सकता है और संख्याओं को 10000000000 तक 3 के साथ विभाजित किया जा सकता है। और ये 3 फ़ंक्शन उसी समय में चलने में सक्षम नहीं हैं जैसे कि कॉन्सिफ़ेरिटी का अर्थ है। लेकिन मैं आपको एक चाल दिखाऊंगा जिससे ये फ़ंक्शन एक ही समय में पुनरावर्ती रूप से चलेंगे: jsFiddle
यह कोड मेरा है।
शरीर का अंग
<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>
जावास्क्रिप्ट भाग
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();
मुझे उम्मीद है कि यह तरीका मददगार होगा।
आप नैरेटिव जावास्क्रिप्ट का उपयोग कर सकते हैं , एक संकलक जो आपके कोड को राज्य मशीन में बदल देगा, प्रभावी रूप से आपको थ्रेडिंग का अनुकरण करने की अनुमति देगा। यह एक "उपज" ऑपरेटर ('->' के रूप में नोट किया गया) को उस भाषा में जोड़कर करता है जो आपको एकल, रैखिक कोड ब्लॉक में अतुल्यकालिक कोड लिखने की अनुमति देता है।
कच्ची जावास्क्रिप्ट में, सबसे अच्छा जो आप कर सकते हैं वह कुछ अतुल्यकालिक कॉल (xmlhttprequest) का उपयोग कर रहा है, लेकिन यह वास्तव में थ्रेडिंग और बहुत सीमित नहीं है। Google गियर्स ब्राउज़र में कई एपीआई जोड़ता है, जिनमें से कुछ को थ्रेडिंग समर्थन के लिए उपयोग किया जा सकता है।
यदि आप किसी AJAX सामान का उपयोग नहीं कर सकते हैं या नहीं करना चाहते हैं, तो एक iframe या दस का उपयोग करें! ;) आप क्रॉस ब्राउज़र तुलनीय मुद्दों या डॉट नेट AJAX आदि के साथ वाक्यविन्यास मुद्दों के बारे में चिंता किए बिना मास्टर पेज के समानांतर में iframes में चलने की प्रक्रिया हो सकती है, और आप मास्टर पेज के जावास्क्रिप्ट (जावास्क्रिप्ट जो इसे आयात किया गया है सहित) से कॉल कर सकते हैं iframe।
उदाहरण के लिए, एक माता-पिता iframe egFunction()में, माता-पिता दस्तावेज़ में कॉल करने के लिए एक बार iframe सामग्री लोड हो गई है (यह अतुल्यकालिक भाग है)
parent.egFunction();
गतिशील रूप से iframes भी उत्पन्न करते हैं इसलिए यदि आप चाहें तो मुख्य HTML कोड उनसे मुक्त है।
एक अन्य संभावित विधि जावास्क्रिप्ट पर्यावरण में एक जावास्क्रिप्ट इंटरप्रेटर का उपयोग कर रहा है।
कई दुभाषियों को बनाकर और मुख्य धागे से उनके निष्पादन को नियंत्रित करके, आप अपने स्वयं के वातावरण में चल रहे प्रत्येक धागे के साथ बहु-थ्रेडिंग का अनुकरण कर सकते हैं।
दृष्टिकोण कुछ हद तक वेब श्रमिकों के समान है, लेकिन आप ब्राउज़र वैश्विक वातावरण में दुभाषिया पहुंच प्रदान करते हैं।
मैंने इसे प्रदर्शित करने के लिए एक छोटा प्रोजेक्ट बनाया ।
इस ब्लॉग पोस्ट में अधिक विस्तृत विवरण ।
जावास्क्रिप्ट में धागे नहीं हैं, लेकिन हमारे पास कार्यकर्ता हैं।
यदि आपको साझा वस्तुओं की आवश्यकता नहीं है, तो श्रमिक एक अच्छा विकल्प हो सकते हैं।
अधिकांश ब्राउज़र कार्यान्वयन वास्तव में सभी कोर में श्रमिकों का प्रसार करेंगे, जिससे आप सभी कोर का उपयोग कर सकेंगे। आप इसका एक डेमो यहां देख सकते हैं ।
मैंने task.js नाम से एक लाइब्रेरी विकसित की है जो ऐसा करने में बहुत आसान है।
कार्य .js सभी कोर पर चलाने के लिए सीपीयू गहन कोड प्राप्त करने के लिए सरलीकृत इंटरफ़ेस (नोड। जेएस, और वेब)
एक उदाहरण होगा
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
});
एचटीएमएल 5 विनिर्देश के साथ आपको उसी के लिए बहुत अधिक जेएस लिखने या कुछ हैक खोजने की आवश्यकता नहीं है।
HTML5 में पेश की गई एक विशेषता वेब वर्कर्स है जो पृष्ठ के प्रदर्शन को प्रभावित किए बिना पृष्ठभूमि में स्वतंत्र रूप से अन्य लिपियों में चल रहा जावास्क्रिप्ट है।
यह लगभग सभी ब्राउज़रों में समर्थित है:
क्रोम - 4.0+
IE - 10.0+
मोज़िला - 3.5+
सफारी - 4.0+
ओपेरा - 11.5+