首页 > 代码库 > C#、PHP与NodeJs性能测试对比

C#、PHP与NodeJs性能测试对比

http://www.prahladyeri.com/2014/06/php-vs-node-js-real-statistics/

在网络编程领域,常用的解决方案就是JSP(SSH)ASP.NETPHP加上LAMP这种架构。不过,现在这个大家庭加入了NodeJS,这个轻量级的基于JavaScript服务端库的平台可以使用异步I/O的方式来提升整体的性能。

 

I/O操作是网络传输中占用资源最大的模块。当Apache服务器接收到请求时,它会将它传输到PHP解释器来执行任何动态脚本的模块。这也是最棘手的模块,如果PHP脚本需要从磁盘或者数据库中读写数据,这回成为整个环节中最慢的一环。如果调用PHP中的file_get_contents()函数,整个线程都会被阻塞直到文件内容被获取到。在此期间服务器不能进行任何操作。如果大量用户同时发出此类请求,那么这些请求都会进入一个等待队列,因为所有的线程都被阻塞了。

而非阻塞操作也是NodeJs最大的特点之一。鉴于NodeJs在它所有的函数中都进行了异步操作,上述场景中的情况在NodeJs中反应就大相径庭。一旦文件调用了fs.readFile函数,该线程会被立刻释放。而当I/O操作结束之后,会自动回调某个在readFile中指定的函数对传入的数据参数进行操作。同时,该线程可以用于处理其他请求。

虽然从原理上可以看出这种机制能够有效地降低用户等待时间,但是还是需要用数据来说明一切。

1.接受请求。
2. 随机生成108千字节的字符串。
3. 将字符串写入到磁盘文件中。
4. 从磁盘文件中读取内容。
5. 将字符串输出到响应流中。

PHP代码 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;

NodeJs代码 server.js:

//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本身的压力测试工具进行2000请求的测试(200/s),结果还是挺惊人的:

#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

事实证明NodeJsPHP大概快上了14倍,结果是非常令人惊讶的,NodeJs杠杠的未来的Web趋势啊。尽管目前NodeJs的生态系统并未十分完善,大部分的面向数据库连接、网络接入、工具等等的模块也是尚未开发完毕,但是根据以上结果,窃以为PHP不会在Web之王的宝座上待太久了。

更新

我也对C#/mono版本进行了测试,结果非常差,大概每个请求的响应时间为40秒,可能是mono的任务库出现了问题,或者我的代码的哪里出错了吧。

namespace Benchmark

{

    using System;

    using System.Web;

    using System.Web.UI;

    using System.Threading.Tasks;

 

    public partial class Default : System.Web.UI.Page

    {

        Random rnd=null;

        public void Page_Load(object sender, EventArgs e)

        {

            //RegisterAsyncTask(new PageAsyncTask(PerformIOasync,PerformIOasync,null,null));

            rnd = new Random ();

            //Task.Run (new Action (PerformIOasync));

            PerformIOasync ();

        }

 

        public async void PerformIOasync()

        {

            string s=""; //generate a random string of 108KB and a random filename

            string fname = rndchar() + rndchar() + rndchar() + rndchar() +".txt";

            for(int i=0;i<108000;i++)

            {

                char ch=rndchar();

                s += ch;

            }

 

            //write s to a file

            //file_put_contents($fname,$s);

 

            var slowTask1 =  Task<string>.Factory.StartNew(()=> WriteToDisk(fname,s));

 

            await slowTask1;

 

            var SlowTask2 = Task<string>.Factory.StartNew(()=> ReadFromDisk(fname,s));

 

            await SlowTask2;

 

            Response.Write(SlowTask2.Result.ToString());

        }

 

        private string WriteToDisk(string fname, string s){

            System.IO.File.WriteAllText (AppDomain.CurrentDomain.BaseDirectory + fname, s);

            return "";

        }

 

        private string ReadFromDisk(string fname, string s){

            return System.IO.File.ReadAllText (AppDomain.CurrentDomain.BaseDirectory + fname);

        }

 

        private char rndchar()

        {

            return (char)rnd.Next (65112);

        }

    }

}