node.js遍历目录及与Python和C的性能比较

前言

这段时间重新梳理node.js,相当于从头开始重新学习了一遍,再次体会了异步的种种精妙之处。本着不断深化学习的想法,找来了npm、express和node的源码来观摩学习,因以前多个项目原因,对于文件模块比较熟悉了解,于是想从文件这块总结些东西出来,回想python3里面有个方法os.walk()用于遍历文件目录的,于是参考其输出完善了node.js的对应实现,在码完代码后进行相互比较运行效率时,发现相差甚远,于是找来Python的源码研究,其实现思路与我写的node.js遍历目录代码是相似的。多次调换调用同步的方法换成异步,其总计的运行时间也没有太大改善,node.js遍历目录代码的输出和python3的os.walk()输出的形式是相同的,在好奇心下找来了性能至尊的C,也写了个遍历目录的方法,对于三种语言的文件遍历进行了简单的测试,比较出相应的性能。

Node.js遍历目录

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

/**
* 同步读文件
* root, dirs, files
* @param dir
* @param callback
*/

//top, dirs, nondirs
function traverse(dir, callback){
     
   var verse = {
     };
   var directory = verse.top = dir;
   var dirs = verse.dirs = [];
   var files = verse.files = [];

   if(isDir(directory)){
     
       var fileNames = fs.readdirSync(directory);
       if(fileNames){
     
           for(var i=0;i<fileNames.length;i++){
     
               var mo = fileNames[i];
               var pathname = path.join(directory,mo);
               if(isDir(pathname)){
     
                   dirs.push(mo);
               }else{
     
                   files.push(mo);
               }
           }
       }
       callback(null,verse);
       if(verse.dirs){
     
           for(var j=0;j<verse.dirs.length;j++){
     
               var next = path.join(directory,verse.dirs[j]);
               traverse(next, callback);
           }
       }
   }

}


/**
* 异步读文件
* @param dir
* @param callback
*/
function superTraverse(dir, callback){
     
   var verse = {
     };
   var directory = verse.top = dir;
   var dirs = verse.dirs = [];
   var files = verse.files = [];

   //fs.lstat(directory,function(err, stats){
     
       if(isDir(directory)){
     
           fs.readdir(directory,function(err, file_arr){
     
               var fileNames = file_arr;
               if(fileNames){
     
                   for(var i=0;i<fileNames.length;i++){
     
                       var mo = fileNames[i];
                       var pathname = path.join(directory,mo);
                       if(isDir(pathname)){
     
                           dirs.push(mo);
                       }else{
     
                           files.push(mo);
                       }
                   }


               }
               callback(verse);
               if(verse.dirs){
     
                   for(var j=0;j<verse.dirs.length;j++){
     
                       var next = path.join(directory,verse.dirs[j]);
                       superTraverse(next, callback);
                   }
               }

           });

       }
   //});



}

/**
* 同步判断是否是目录
* @param path
* @returns {*}
*/
function isDir(path){
     
   return fs.lstatSync(path).isDirectory();
}


var path0 = 'E:\\SMB2';
path0 = 'E:\\IOT';
console.time('test0');
if(fs.existsSync(path0)){
     
   superTraverse(path0, function(obj){
     
       //console.log('obj', obj, Date.now());
   });
   //traverse(path0,function(err, obj){
     
   //
   //    //console.log(err, obj);
   //
   //});
}

//statSync:50.957ms,
console.timeEnd('test0');
console.log(Date.now());

Python遍历目录

import os
import time


if __name__ == '__main__':
   num = 0
   starttime = time.time()
   path = ['E:\\IOT']
   for p in path:
       print(p, ':-------------------------------------- ')
       for (root, dirs, files) in os.walk(p):
           num = num + 1
           # print('root: ', root, ' ,num: ', num)
           # print('dirs: ', dirs, ' ,num: ', num)
           # print('files: ', files, ' ,num: ', num)
       print(p, '-----------------END--------------------- ')
   endtime = time.time()
   print(endtime - starttime, starttime, endtime)
   print(num)

C遍历目录

#include 
#include 
#include 

void listFiles(const char * dir);

int num = 0;
int main()
{
     

   char dir[200] = "E:\\IOT";
   long start, finish;
   double Total_time;
   start = clock();

   listFiles(dir);
   finish = clock();

   Total_time = (double)(finish - start)/1000;
   printf("\n函数运行时间:%0.3f秒 \n", Total_time);
   printf("总数量: %d\n",num);
   return 0;
}

void listFiles(const char * dir)
{
     
   char dirNew[200];
   strcpy(dirNew, dir);
   strcat(dirNew, "\\*.*");    // 在目录后面加上"\\*.*"进行第一次搜索

   intptr_t handle;
   struct _finddata_t findData;


   handle = _findfirst(dirNew, &findData);
   if (handle == -1)        // 检查是否成功
       return;

   do
   {
     
       if (findData.attrib & _A_SUBDIR)
       {
     
           if (strcmp(findData.name, ".") == 0 || strcmp(findData.name, "..") == 0)
               continue;
           num ++;
           printf("文件夹:\n");
           printf("%s\n",findData.name);


           // 在目录后面加上"\\"和搜索到的目录名进行下一次搜索
           strcpy(dirNew, dir);
           strcat(dirNew, "\\");
           strcat(dirNew, findData.name);

           listFiles(dirNew);
       }
       else
       {
     
       	printf("文件:\n");
       	printf("%s\n",findData.name);
       }
   } while (_findnext(handle, &findData) == 0);


   _findclose(handle);    // 关闭搜索句柄
}

性能比较

1.遍历目录E:\SMB2

文件夹数量:69
node.js版本:v6.12.0
python版本:v3.5.5
c编译器mingw-get-setup版本: v0.602.22340.1

序号 node.js python3 c
1 56ms 14ms 8ms
2 40ms 11ms 8ms
3 37ms 11ms 8ms
4 40ms 11ms 7ms
5 40ms 12ms 8ms
6 41ms 10ms 7ms
7 42ms 10ms 7ms
8 41ms 11ms 8ms
9 41ms 10ms 8ms
10 39ms 11ms 8ms

2.遍历目录E:\IOT

文件夹数量:70405
node.js版本:v6.12.0
python版本:v3.5.5
c编译器mingw-get-setup版本: v0.602.22340.1

序号 node.js python3 c
1 72.470s 13.793s 7.678s
2 57.040s 13.525s 7.586s
3 56.380s 13.464s 7.646s
4 56.930s 13.489s 7.656s
5 56.810s 13.546s 7.678s
6 56.520s 13.530s 7.640s
7 69.380s 13.517s 7.708s
8 57.980s 13.586s 7.870s
9 57.390s 13.493s 7.534s
10 56.830s 13.579s 7.574s

3.性能总结

这样的测试结果尽管不能完全反应出一种语言的优劣,但从中还是可以窥见些个中情况,I/O密集型和CPU密集型,众所周知对于CPU密集型业务Node并不擅长,因为其单线程异步非阻塞I/O,诚然在调用了遍历目录方法不用像其他语言一样等待返回结果然后再往下运行,而可以直接运行下面的其它代码,当遍历目录执行完成后触发回调事件,获取结果,可以有无比宽广的想象空间,毕竟我们生活的世界是按照异步方式非阻塞运行。但从I/O密集型的方面来考证,在实现相同的功能情况下,尽管是Node所擅长的I/O领域,在代码的执行效率上,其并不见得优势有多明显,当然可以使用C/C++模块编译的方法直接运行,获得C/C++的高效率,事情有两面性,C/C++的程序编程的门槛更高,不能像封装好的node.js和Python或者Java一样快速获取编程的愉悦快感,不用过多考虑垃圾的回收和内存的高效使用。

你可能感兴趣的:(负熵的Node笔记,node,node.js,python,python3,c)