nodejs文件IO性能测试
发布于 3年前 作者 edwin 2356 次浏览

刚开始接触nodejs,做这个测试目的是为了

1、熟悉nodejs的语法 2、比较异步和同步实现的性能差异
3、比较nodejs和java实现的性能差异

实现功能: 统计文件系统中某个目录的大小。

运行环境: winxp nodejs 0.6.17 jdk1.6.0_10-rc2

代码见附件: 代码1、syncDirTree.js 同步 代码2、asyncDirTree.js 小范围实现异步 代码3、asyncDirTree1.js 全部异步实现

    var fs = require('fs');
var Path = require('path');

var queue = new Array();
var root = "d:\\tools";

var tree = {};

function TreeNode(filename){
    this.path = filename;
    this.children = [];
    this.isCaculating = true;
    this.size = 0;
    this.childrenNum = 0;
    this._childBeenAdded = 0;
    this._callback;

    this.expand = function(callback){
        var fs_stat;
        try{
            fs_stat =fs.statSync(this.path);
        }catch(e){
            callback(new Error(e),0);
            return;
        }
        if(!fs_stat.isDirectory()){ //has no children
            this.isCaculating = false;
            this.size = fs_stat.size;
            callback(null, fs_stat.size);
        }else{
            var me = this;
            this.callback = callback;
            fs.readdir(this.path, function(err, files){
                me.childrenNum = files.length;
                if(files.length==0){    //empty folder
                    me.isCaculating = false;
                    me.callback(null,0);
                    return;
                }
                files.forEach(function(file){
                    var _filename =Path.join(me.path,file);
                    var _treeNode = new TreeNode(_filename);
                    //console.log(this);
                    me.children.push(_treeNode);
                    _treeNode.expand(function(err,size){
                        me.size += size;
                        me._childBeenAdded++;
                        if(me._childBeenAdded >= me.childrenNum){
                            me.isCaculating = false;
                            me.callback(null,me.size);
                        }
                    })
                });
            })
        }
    }
}

var rootNode = new TreeNode(root);
var begin = new Date().getTime();
rootNode.expand(function(err,size){
    if(!err){
        var end = new Date().getTime();
        console.log('elapse time: '+ (end - begin));
        console.log('size:' + size);
    }
})

代码4、FileSize.java java实现

    public class FileSize {
    
    public long expand(File file){
        if(!file.isDirectory()){
            //this.size = file.length();
            return file.length();
        }
        File[] files = file.listFiles();
        if(files.length == 0)return 0;
        long _size =0;
        for(int i=0;i<files.length;i++){
            _size += expand(files[i]);
        }
        return _size;
    }
    
    public static void main(String[] args) {
        long begin = System.currentTimeMillis();
        File file = new File("d:\\tools");
        FileSize fs = new FileSize();
        System.out.println( fs.expand(file) );
        long end = System.currentTimeMillis();
        System.out.println( end - begin );
    }

测试目录为d:\tools,17,007,212,070 字节,19万个左右文件和目录

测试结果: 代码1-3 执行时间差不多,为22秒左右 代码4执行时间为9秒左右

结论: 文件操作占用了绝大部分时间,所以nodejs异步和同步实现的性能差异不大。 java的文件操作优于nodejs,速度快1倍。

测试有些粗陋,测试结果仅供参考。也请大家审查,多提意见。

4 回复

这也证明nodejs还是不太适合文件IO密集型的应用

NodeJS的一大优势就是非阻塞的IO操作,即IO操作时立即返回干点儿别的活儿~ 但是就文中测试实例而言,几乎全是IO操作,所谓“别的活儿”也只是加加文件大小可以忽略不计~ 因此,异步与同步就区别不大了~
或者这时,多线程的优势就体现出来了(一个人可以模拟出N个人在干活儿)~

楼主的代码中,读取文件属性用的是阻塞函数fs.statSync(),因此测试是不准确的。

且看以下代码:

var fs = require('fs');
var path = require('path');
var THREAD = require('os').cpus().length;

var expand = function (file, callback) {
  fs.stat(file, function (err, stats) {
    if (err)
      return callback(err);
    if (!stats.isDirectory()) {
      return callback(null, stats.size);
    } else {
      fs.readdir(file, function (err, files) {
        if (err)
          return callback(err);
        for (var i = 0, len = files.length; i < len; i++)
          files[i] = path.join(file, files[i]);
        var size = 0;
        var finish = 0;
        var threadFinish = function () {
          finish++;
          if (finish >= THREAD)
            return callback(null, size);
        };
        var next = function () {
          var f = files.pop();
          if (!f)
            return threadFinish();
          expand(f, function (err, s) {
            if (err)
              return callback(err);
            size += s;
            next();
          });
        };
        for (var i = 0; i < THREAD; i++)
          next();
      });
    }
  });
};

var ts = new Date();
expand('d:\\tools', function (err, size) {
  if (err)
    console.log(err.stack);
  var te = new Date();
  console.log('Size: ' + size);
  console.log('Spent: ' + (te - ts));
});

运行结果:

Java程序需要6.8秒

楼主的Node.js程序需要27.4秒

经过改良后的Node.js程序需要10秒

结论:虽然Node.js程序比Java程序稍慢(这是正常的),但是差异并不像楼主所说的那么离谱。

enter image description here

回到顶部