हालांकि यह सच है कि node.js की एसिंक्रोनस प्रकृति इसे शानदार बनाती है, यह अभी भी एक ईवेंट लूप में सर्वर पर एक ही थ्रेड में चलती है। क्लस्टर के साथ एक node.js ऐप को मल्टीथ्रेड करने से आप ऐप की बाल प्रक्रियाओं को अपने स्वयं के धागे में फेंकने की अनुमति देते हैं, जिससे आप बहु-कोर सर्वर का बेहतर उपयोग कर सकते हैं। मैंने कुछ समय पहले एक गेम सर्वर आर्किटेक्चर बनाया था जो क्लस्टर और जेएमक्यू (ज़ीरोएमक्यू) को मल्टीथ्रेड करने के लिए इस्तेमाल करता था और प्रक्रियाओं को आसानी से विभिन्न चैनलों पर संदेशों को आसानी से भेजने में सक्षम बनाता था। मैंने आशा व्यक्त की है कि आर्किटेक्चर को नीचे दिए गए उदाहरण में सरलीकृत करने में मदद मिलेगी कि कैसे multithreaded node.js को एक साथ रखा जा सकता है। मैं माफी माँगता हूँ अगर यह थोड़ा किसी न किसी तरह है, यह साल पहले था और मैं अपेक्षाकृत समय में नोड के लिए नया था;)
आदर्श रूप में, आप एक ही लिपि में मास्टर/बच्चे के लिए घोंसला सब कुछ नहीं करना चाहते हैं, लेकिन मैं यह अनुमान लगाया गया कि यह आपको कॉपी/पेस्ट/चलाने के लिए सबसे आसान तरीका था :)
जैसा कि आपने अपनी टिप्पणी में उल्लेख किया है, मैंने क्लस्टरिंग का एक अच्छा उदाहरण दिया है, लेकिन आपके विशिष्ट उपयोग मामले में फिट नहीं है, जहां तक आसपास के सब कुछ भेजना । मेरे पास बहुत समय नहीं था, इसलिए मैंने इसे अपनी आवश्यकताओं के लिए काम करने के लिए अपना उदाहरण अनुकूलित किया। इस एक शॉट दे दो:
बड़े पैमाने पर request.js
var cluster = require('cluster');
var zmq = require('zmq');
module.exports = {
_childId : null,
_urls : [],
_threadCount : 1,
_readyThreads : 0,
_callbacks : {},
zmqReceive : null, //the socket we receive on for this thread
zmqMaster : null, //the socket to the master
zmqChildren : {}, //an object storing the sockets for the children
setThreads : function(threadCount) {
this._threadCount = threadCount;
},
add : function(url , cb) {
this._urls.push({url: url, cb : cb });
},
run : function() {
if(cluster.isMaster) {
this._masterThread();
} else {
this._childThread();
}
},
_masterThread : function() {
console.log('Master Process Starting Up');
this.zmqReceive = zmq.socket('pull').bindSync('ipc://master.ipc');
//bind handler for messages coming into this process using closure to allow us to access the massrequest object inside the callback
(function(massRequest) {
this.zmqReceive.on('message' , function(msg) {
msg = JSON.parse(msg);
//was this an online notification?
if(msg && msg.status == 'Online') {
massRequest._threadReady();
return; //we're done
}
if(msg && msg.html) {
//this was a response from a child, call the callback for it
massRequest._callbacks[ msg.sender ].call(massRequest , msg.html);
//send the child another URL
massRequest._sendUrlToChild(msg.sender);
}
});
}).call(this , this);
//fork 4 child processes and set up the sending sockets for them
for(var i=0; i < this._threadCount; ++i) {
//set up the sending socket
this.zmqChildren[i] = zmq.socket('push').connect('ipc://child_' + i + '.ipc');
//fork the process and pass it an id
cluster.fork({
_childId:i
});
}
},
_sendUrlToChild : function(child) {
//if there's no urls left, return (this would also be a good place to send a message to the child to exit gracefully)
if(!this._urls.length) return;
//grab a url to process
var item = this._urls.pop();
//set the callback for the child
this._callbacks[child] = item.cb;
this.zmqChildren[child].send(JSON.stringify({ url:item.url }));
},
_processUrls : function() {
for(var i=0; i < this._threadCount; ++i) {
this._sendUrlToChild(i);
}
},
_threadReady : function() {
if(++this._readyThreads >= this._threadCount) {
//all threads are ready, send out urls to start the mayhem
console.log('All threads online, starting URL processing');
this._processUrls();
}
},
_childProcessUrl : function(url) {
console.log('Child Process ' + this.childId + ' Handling URL: ' + url);
//do something here to scrape your content however you see fit
var html = 'HTML';
this.zmqMaster.send(JSON.stringify({ sender:this.childId, html:html }));
},
_childThread : function() {
//get the child id that was passed from cluster
this.childId = process.env._childId;
console.log('Child Process ' + this.childId + ' Starting Up');
//bind the pull socket to receive messages to this process
this.zmqReceive = zmq.socket('pull').bindSync('ipc://child_' + this.childId + '.ipc');
//bind the push socket to send to the master
this.zmqMaster = zmq.socket('push').connect('ipc://master.ipc');
//bind handler for messages coming into this process
(function(massRequest) {
this.zmqReceive.on('message' , function(msg) {
msg = JSON.parse(msg);
console.log('Child ' + this.childId + ': ' + msg);
//handle the url
if(msg && msg.url) massRequest._childProcessUrl(msg.url);
});
}).call(this , this);
//let the master know we're done setting up
this.zmqMaster.send(JSON.stringify({sender:this.childId,status:'Online'}));
},
}
demo.js
var mr = require('./mass-request.js');
mr.setThreads(4);
mr.add('http://foo.com' , function(resp) {
console.log('http://foo.com is done');
});
mr.add('http://bar.com' , function(resp) {
console.log('http://bar.com is done');
});
mr.add('http://alpha.com' , function(resp) {
console.log('http://alpha.com is done');
});
mr.add('http://beta.com' , function(resp) {
console.log('http://beta.com is done');
});
mr.add('http://theta.com' , function(resp) {
console.log('http://theta.com is done');
});
mr.add('http://apples.com' , function(resp) {
console.log('http://apples.com is done');
});
mr.add('http://oranges.com' , function(resp) {
console.log('http://oranges.com is done');
});
mr.run();
एक ही फ़ोल्डर में उन रखो और node demo.js
चलाते हैं।
मैं यह भी कहना चाहिए कि इस के बाद के आधार मेरे अन्य परियोजनाओं में से एक है कि [0MQ] का उपयोग [http://zeromq.org/] से खींचा गया था, तो आप उस [के साथ स्थापित की आवश्यकता होगी इसके लिए मॉड्यूल Node.js] [https://github.com/JustinTulloss/zeromq.node]npm install zmq
और जाहिर है क्लस्टर मॉड्यूल।आप जेडएमक्यू भागों को इंटरप्रोसेस संचार की किसी भी अन्य विधि के लिए स्वैप कर सकते हैं जो आप चाहते हैं। यह सिर्फ एक होता है जिसे मैं परिचित था और इस्तेमाल किया था।
संक्षिप्त अवलोकन: मास्टर थ्रेड AKA स्क्रिप्ट जो रन() विधि को कॉल करती है वह एक्स बच्चों को स्पिन करेगी (सेट थ्रेड को कॉल करके सेट किया जा सकता है)। वे बच्चे ज़ीरोएमक्यू सॉकेट के माध्यम से मास्टर थ्रेड पर वापस रिपोर्ट करते हैं जब वे प्रारंभ करना समाप्त कर देते हैं। एक बार सभी धागे तैयार हो जाने के बाद, मास्टर स्क्रिप्ट बच्चों को यूआरएल भेजती है ताकि वे एचटीएमएल को चला सकें और ला सकें। वे एचटीएमएल को मास्टर पर लौटते हैं जहां यह उस यूआरएल के लिए उचित कॉलबैक फ़ंक्शन में भेजता है और फिर बच्चे स्क्रिप्ट में एक और यूआरएल भेजता है। हालांकि यह एक सही समाधान नहीं है, कॉलबैक फ़ंक्शन अभी भी मुख्य (मास्टर) थ्रेड में बाधा डालने जा रहे हैं क्योंकि आप आसानी से उन्हें किसी अन्य थ्रेड पर नहीं ले जा सकते हैं। उन कॉलबैक में क्लोजर/वेरिएबल्स/आदि हो सकते हैं जो बिना किसी ऑब्जेक्ट शेयरिंग मैकेनिज्म के पैरेंट थ्रेड के बाहर ठीक से काम नहीं कर सकते हैं।
Anywho, अगर तुम यहाँ मेरी छोटी डेमो ऊपर स्पिन आप 4 धागे "संसाधन" यूआरएल देखेंगे (वे वास्तव में सादगी खातिर यूआरएल लोड नहीं है)।
उम्मीद है कि मदद करता है कि;)
कैसे बच्चे की प्रक्रिया js धागे में अनुरोध मदद से चल रहा होगा? एचटीपी अनुरोध पहले से ही जेएस धागे के बाहर मौजूद हैं। Http://nodejs.org/api/http.html#http_class_http_agent – generalhenry
दिलचस्प देखें। तो कई यूआरएल कॉल के काम को विभाजित करने में दो या दो से अधिक प्रक्रियाएं होने से प्रक्रिया तेज नहीं होगी? प्रतिक्रियाओं को संभालने के लिए सभी कॉल और दूसरे को बनाने के लिए एक थ्रेड के बारे में क्या? –
एकाधिक जेएस धागे का उपयोग करने का एकमात्र कारण यह है कि जेएस धागे बाधाएं हैं। Node.js की एसिंक्रोनस प्रकृति को देखते हुए शायद ही कभी यह मामला है जब तस्वीर में आईओ भी है। तो बच्चों को प्रसंस्करण बंद करना केवल तभी समझ में आता है जब आप क्रिप्टो जैसे सीपीयू गहन काम कर रहे हों। मोज़िला व्यक्तित्व एक अच्छा उदाहरण है। – generalhenry