在網(wǎng)頁編程領(lǐng)域,我一直使用ASP.NET或LAMP技術(shù)寫代碼,這成為我生活的絕大部分內(nèi)容?,F(xiàn)在,新的亮點(diǎn)是node.js。它是一個在服務(wù)器端運(yùn)行javascript的框架,并據(jù)說通過使用異步I/ O,提升了一些性能。

  該理論認(rèn)為,同步I/O 阻塞模型的工作原理是這樣的:    

   (注* 關(guān)于異步非阻塞模型的工作原理,可參見:  是什么讓Node.js比Java更快? )

 

  I / O是一個典型的網(wǎng)絡(luò)事務(wù)(web transaction)中的最昂貴的部分。當(dāng)一個請求到達(dá)Apache Web服務(wù)器,它傳遞給PHP解釋器來執(zhí)行腳本的動態(tài)內(nèi)容。現(xiàn)在到了棘手的部分 - 如果PHP腳本想要從磁盤/數(shù)據(jù)庫讀取或存取數(shù)據(jù),這就成了最慢的一環(huán)。當(dāng)你調(diào)用PHP函數(shù) file_get_contents(),整個線程被阻塞,直到內(nèi)容獲取完成!直到你的腳本獲得文件內(nèi)容,服務(wù)器不能做任何事情。想像一下當(dāng)并發(fā)請求增加數(shù)倍時,會發(fā)生什么?他們要排隊,因?yàn)闆]有可用的線程可以做這份工作,因?yàn)樗麄兌急籌/O阻塞了!

  這里談到了 node.js 中獨(dú)特的賣點(diǎn)緣于 node.js 在幾乎所有的功能中都使用異步I / O,在上述方案中,只要服務(wù)器線程一被釋放,文件檢索功能(fs.readFile)就被調(diào)用。然后,一旦在I / O完成后,節(jié)點(diǎn)才會執(zhí)行傳進(jìn)來的回調(diào)函數(shù)(早些時候通過fs.readFile)。在此期間,該有價值的線程就可以用于服務(wù)其它一些請求。

  所以,這就是關(guān)于它的理論。但我不是那種只是因?yàn)樗淮笏列麄骰蛘呙總€人都使用它就接受新風(fēng)潮的人。不,我想在知道事實(shí)真相,并親自來驗(yàn)證它。我想看看這個理論是否能經(jīng)得起實(shí)際操作的考驗(yàn)。 

  所以為了測試它,我自己寫了兩個簡單的腳本 —— 一個在PHP(托管在apache2的),另一個是JavaScript(托管在node.js上的)。測試本身是非常簡單的。該腳本將:

  1,接受請求。 

  2,生成一個隨機(jī)的108千字節(jié)的字符串。 

  3,將字符串寫到磁盤的文件上。 

  4,從磁盤中讀取內(nèi)容。 

  5,在返回的響應(yīng)流中返回字符串。 

  這是第一個腳本,index.php文件:

<?php
//index.php
$s=""; //generate a random string of 108KB and a random filename
$fname = chr(rand(0,57)+65).chr(rand(0,57)+65).chr(rand(0,57)+65).chr(rand(0,57)+65).'.txt';
for($i=0;$i<108000;$i++)
{
$n=rand(0,57)+65;
$s = $s.chr($n);
}
 
//write s to a file
file_put_contents($fname,$s);
$result = file_get_contents($fname);
echo $result;

  這是第二個腳本

//server.js
var http = require('http'); 
var server = http.createServer(handler);
 
function handler(request, response) {
    //console.log('request received!');
    response.writeHead(200, {'Content-Type': 'text/plain'});
 
    s=""; //generate a random string of 108KB and a random filename
    fname = String.fromCharCode(Math.floor(65 + (Math.random()*(122-65)) )) +
        String.fromCharCode(Math.floor(65 + (Math.random()*(122-65)) )) +
        String.fromCharCode(Math.floor(65 + (Math.random()*(122-65)) )) + 
        String.fromCharCode(Math.floor(65 + (Math.random()*(122-65)) )) + ".txt";
 
    for(i=0;i<108000;i++)
    {
        n=Math.floor(65 + (Math.random()*(122-65)) );
        s+=String.fromCharCode(n);
    }
 
    //write s to a file
    var fs = require('fs');
    fs.writeFile(fname, s, function(err, fd) {
            if (err) throw err;
            //console.log("The file was saved!");
            //read back from the file
            fs.readFile(fname, function (err, data) {
                if (err) throw err;
                result = data;
                response.end(result);
            }); 
        }
    );
}
 
server.listen(8124);
console.log('Server running at http://127.0.0.1:8124/');

  然后,然后我通過apache評測工具,向他們兩者一共發(fā)了2000個請求(200并發(fā))。當(dāng)我看到時間統(tǒng)計結(jié)果,我大吃一驚: 

#PHP:
Concurrency Level:      200
Time taken for tests:   574.796 seconds
Complete requests:      2000
 
#node.js:
Concurrency Level:      200
Time taken for tests:   41.887 seconds
Complete requests:      2000

  真相大白了。node.js比PHP快14倍!這結(jié)果是驚人的。它簡直意味著node.js將在不久的未來成為編寫性能驅(qū)動應(yīng)用程序事實(shí)上的標(biāo)準(zhǔn),這也是毫無疑問的!

  大家一致認(rèn)為NodeJS生態(tài)系統(tǒng)還沒有被廣泛開發(fā)掘,并且大多數(shù)節(jié)點(diǎn)模塊,比如數(shù)據(jù)庫連接,網(wǎng)絡(luò)接入,公用設(shè)施等,正在積極開發(fā)中。但盡管如此,看到這些結(jié)果后,實(shí)在是太顯而易見了。在發(fā)展node.js應(yīng)用程序所花費(fèi)的任何額外的努力都是非常值得的。 PHP的可能仍然保持著“網(wǎng)頁之王”的狀態(tài),但是作為焦點(diǎn)的node.js,我估計這種狀態(tài)不會持續(xù)很長時間!

  更新 

  從下面一節(jié)看了一些評論之后,我覺得有義務(wù)也創(chuàng)建一個C#/mono 版本。不幸的是,這個已經(jīng)被證明是最慢的一組(約40秒1個請求)。也許是我的程序?qū)戝e了,或者我的代碼有什么錯誤。一旦等我閑下來我就會解決它,也許我的下一篇文章就是ASP.NET vs node.js vs PHP!。

  參考文獻(xiàn):

  1 https://en.wikipedia.org/wiki/Node.js

  2 http://notes.ericjiang.com/posts/751

  3 http://nodejs.org

  4.https://code.google.com/p/node-js-vs-apache-php-benchmark/wiki/Tests

  哈爾濱品用軟件有限公司致力于為哈爾濱的中小企業(yè)制作大氣、美觀的優(yōu)秀網(wǎng)站,并且能夠搭建符合百度排名規(guī)范的網(wǎng)站基底,使您的網(wǎng)站無需額外費(fèi)用,即可穩(wěn)步提升排名至首頁。歡迎體驗(yàn)最佳的哈爾濱網(wǎng)站建設(shè)