所以如果我寫出以下的code, 就會造成單一request block後面的request, 這是一個echo server, 當有資料進來的時候, 會呼叫function(data), 如果我在這個function裡面作一些time consuming的動作, 就會造成其他的request delay.
var net = require("net"); // echo server example var TCPServer = net.createServer(function (socket){ // on "data" event socket.on("data", function(data){ request = data.toString('utf8'); now = new Date().getTime(); // it will wait for 5 seconds to block following request while(new Date().getTime() < now + 5000) { // do nothing } socket.write(request); }); }); TCPServer.listen(7777, "127.0.0.1");
所以針對一些cpu bound的運算, 目前我查到的解法有兩種, 第一種就是普通的fork,
fork出child process去執行你要得command, 等到執行結束, 在利用callback繼續下去, 這樣就可以讓CPU bound的運算不至於影響到其他的request.
var net = require("net"); var sys = require('sys'); var exec = require('child_process').exec; // echo server example var TCPServer = net.createServer(function (socket){ sys.debug('new socket coming!'); socket.on('data', function(d) { sys.debug('new data coming ' + d); var sleep = exec('sleep 5', function(error, stdout, stderr) { socket.write('finish job: ' + d); }); }); }); TCPServer.listen(7777, "127.0.0.1");
Webworker, 這是node.js的某一個ext module, 他是利用unix domain socket來達到IPC (inter process communication), 他提供比較抽象的API, 透過postMessage, onmessage這種API,我下面的實做只提供message傳遞, 當worker事情做完就把結果回傳給server. postMessage 的參數需要以JSON的格式傳過去, 在postMessage的時候可以把file descriptor當第二個參數傳給worker process, 但是這部份我一直無法成功實驗出來...
Server.js
=================
var net = require("net"); var sys = require('sys'); var Worker = require('webworker').Worker; var index = 0; var workers = []; var socks = {}; var sock_num = 0; for(var i = 0; i < 8; i++) { workers.push(new Worker('')); // when some result message return from worker process workers[i].onmessage = function(msg) { var sock_index = msg.data.index; var result = msg.data.result; sys.debug('master: ' + sock_index); socks[parseInt(sock_index)].write(result); }; } // echo server example var TCPServer = net.createServer(function (socket){ var l = sock_num; sock_num++; socks[l] = socket; // when client send data socket.on('data', function(d) { var data = d.toString('utf8').trim(); sys.debug(index + ' worker data: ' + data); sys.debug('socks: ' + l); workers[index].postMessage({'text': data, 'index': index, sock_index: l}); index++; }); // when client close connection socket.on('close', function() { sys.debug('delete socks: ' + l); delete socks[l]; }); }); TCPServer.listen(7777, "127.0.0.1");
Worker.js
=================
var http = require('http'); var net = require('net'); var sys = require('sys'); function sleep() { var now = new Date().getTime(); // it will wait for 5 seconds to block following request while(new Date().getTime() < now + 5000) { ; } }; onmessage = function(msg) { sys.debug('worker index: ' + msg.data.index); sys.debug('worker sock_index: ' + msg.data.sock_index); sys.debug('worker text: ' + msg.data.text); var result_text = msg.data.text + ' processed\n'; // time consuming operation sleep(); sys.debug('worker after sleep'); postMessage({index: msg.data.sock_index, result: result_text}); }; onclose = function() { sys.debug('Worker shuttting down.'); };
下面這是後來gibson試出來的用法~
master.js
=====================
var http = require('http'); var sys = require('sys'); var path = require('path'); var net = require('net'); var Worker = require('webworker').Worker; var workers = []; var wid=0; for (var i = 0; i < 8; i++) { workers[i] = new Worker(path.join(__dirname, 'worker.js')); } net.createServer(function(socket){ socket.pause(); wid = (++wid) % 8; sys.debug('pass to worker '+ wid + ' fd:' + socket.fd); workers[wid].postMessage({'wid':wid}, socket.fd); }).listen(8080);worker.js
=====================
var http = require('http'); var sys = require('sys'); var net = require('net'); var srv = net.createServer(function(socket){ socket.on('data', function(data){ buf = data.toString('utf8'); socket.write('['+process.pid+'] received: ' + buf); }); }); onmessage = function(msg) { sys.debug('worker received msg.data.wid: ' + msg.data.wid); sys.debug('worker received msg.fd: ' + msg.fd); var socket = net.Stream(msg.fd); socket.type = srv.type; socket.server = srv; socket.resume(); srv.emit('connection', socket); };Reference: http://blog.mixu.net/2011/02/01/understanding-the-node-js-event-loop/ http://blog.std.in/2010/07/08/nodejs-webworker-design/ http://developer.yahoo.com/blogs/ydn/posts/2010/07/multicore_http_server_with_nodejs/ http://nodejs.org/docs/v0.4.7/api/child_processes.html
沒有留言:
張貼留言