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

2017-04-21 11:25:31 +08:00
 actto

主要操作:(文件去重)

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

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

需要处理几百万个文件.

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

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

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

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/356372

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX