V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
actto
V2EX  ›  Node.js

nodejs, 多 IO 操作,如何提高执行效率??

  •  
  •   actto · 2017-04-21 11:25:31 +08:00 · 4889 次点击
    这是一个创建于 2802 天前的主题,其中的信息可能已经有所发展或是发生改变。

    主要操作:(文件去重)

    function files_do(){
        let MD5 = 读(buffer 生成 MD5);
        if(从数据库找相同 MD5 的值.Count()==0){
           //没找到
           数据库.insert(文件信息);
        }else{
           //有相同值
           文件移动(原路径, 目标路径);
        }
        setTimeout(function(){
        	files_do()
        },0)
    }
    

    目前 5 万个文件(大小: 几 k 到十几 M 都有), 大概需要 6 个小时多..

    需要处理几百万个文件.

    有什么办法能进一步提高执行效率??

    15 条回复    2017-04-22 14:19:20 +08:00
    TJT
        1
    TJT  
       2017-04-21 12:24:49 +08:00   ❤️ 1
    先分析性能消耗在哪里。可能的优化方法有数据库所有的 MD5 放到 Set 里面,这样就直接干掉数据库了、多线程 /多进程、用 C 重写。
    crayygy
        2
    crayygy  
       2017-04-21 12:34:54 +08:00 via iPhone   ❤️ 1
    粗略的想了一下,主要的消耗有两个,一是读文件, IO 消耗比较大,二是数据库查询,消耗也不小。第一个没办法,如果你对内容要求不多,直接对整个文件做校验或许就可以了。数据库的话就像楼上说的,几万个也不多,直接存在内存里,然后统一写数据库。
    XiaoxiaoPu
        3
    XiaoxiaoPu  
       2017-04-21 13:14:05 +08:00   ❤️ 1
    不要直接比较 md5 ,先比较文件长度,再比较文件的部分内容(比如开头 1 KiB ),最后比较 md5 。
    keller
        4
    keller  
       2017-04-21 13:18:50 +08:00   ❤️ 1
    不要直接对比 md5 先对比文件大小 相同大小的文件再做 md5 对比
    actto
        5
    actto  
    OP
       2017-04-21 17:39:34 +08:00
    谢谢大家!!!
    1, 我目前就用的内存数据库, 定期写回 db 文件里..所以目前数据库查询效率还可以.
    2, "先比较文件大小" 不可行..因为 db.insert(文件信息) 必须有 MD5 值(因为后面的文件需要和它比对)....也还是得读一遍文件 buffer...
    3, 现在考虑用 C++写 多线程读 buffer,并生成 MD5 的操作..先写入数据库..全部结束后, 数据库查重复, 再移动文件.
    lldld
        6
    lldld  
       2017-04-21 18:40:40 +08:00 via iPhone
    @actto 楼上
    @XiaoxiaoPu 的建议不错。
    读文件的时候不要读整个文件求 md5.

    可以分三步:
    1) 按照文件大小和文件前 256bytes 的 md5 来确定可能会重复的文件
    2) 对 1 的结果求整个文件的 md5, 确定重复的文件
    3) 去重
    coderfox
        7
    coderfox  
       2017-04-21 22:57:49 +08:00 via Android
    读 buffer 生成 MD5 可以换成调用 md5 终端指令。也许能改善,取决于 node 的 md5 实现如何。
    breeswish
        8
    breeswish  
       2017-04-22 00:07:53 +08:00
    md5 没啥性能瓶颈的,一般单核每秒都有几百兆。楼主需要先看一下 node CPU 是否跑满单核了,按照楼主 po 的代码来看是有异步性能浪费的( setTimeout ),当然实际代码也许不是长成这样。如果单核已经跑满了,可以考虑上多个进程并行运行。
    优化的上线应当接近于这 5 万个文件全部读取一遍的性能。
    breeswish
        9
    breeswish  
       2017-04-22 00:16:50 +08:00
    另外楼主可以考虑直接将文件流 pipe 到 hash ,可以避免频繁的 buffer alloc ,进一步压榨一些性能。
    用 C++ 生成 md5 就不用想了, nodejs 人家不是用 js 算的 md5 ,是 openssl 计算的,自己写的效率一般不会更高。
    breeswish
        10
    breeswish  
       2017-04-22 00:23:12 +08:00
    当然上面说的那些的前提是不频繁访问数据库。数据库一般是个瓶颈,一楼已经给出优化数据库的方法了。
    不过不建议用 C 重写 :P 这个需求的终极瓶颈理论上在 IO ,如果测下来瓶颈不在 IO 上那么就是可以优化的。以及既然终极瓶颈是 IO ,那么我猜测不用异步写 C 的话会写得单核性能比 nodejs 版还要低。
    actto
        11
    actto  
    OP
       2017-04-22 00:56:30 +08:00 via Android
    @breeswish 谢谢给出的建议!!!
    我的代码确实有用到 setTimeout ,因为希望页面上能反应出进度,给 dom 操作留点时间。(electron 小程序,数据库用的 LokiJS)
    整体代码就是递归循环整个文件夹,找到所有的文件去重。重复文件放在固定文件夹,等待人工检查。
    cpu 目前占用 20%不到(18%— 19%左右)。
    guokeke
        12
    guokeke  
       2017-04-22 05:45:24 +08:00
    @breeswish 你玩 telegram 吗?喵?
    breeswish
        13
    breeswish  
       2017-04-22 12:10:15 +08:00
    @guokeke breezewish
    breeswish
        14
    breeswish  
       2017-04-22 12:19:34 +08:00
    @actto 这么来说目测你的 IO 用的也都是同步的 IO 了……?那么你首先要做的是全改成异步的 IO ,然后用上一些异步流程控制的库比如 caolan/async 来进行控制(比如可以用上它的 queue )。然后 setTimeout 可以去掉了
    qfdk
        15
    qfdk  
       2017-04-22 14:19:20 +08:00 via iPhone
    你把文件合并一下 大体看看读取 500m 是个啥速度 按道理 应该不慢 另外读取文件有异步和同步两种方式
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2921 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 71ms · UTC 13:25 · PVG 21:25 · LAX 05:25 · JFK 08:25
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.