Rem*_*i.b 5 bash performance merge file disk-io
有 8100 万个文件 (!) 存储在远程机器上的一个目录中。所有文件都以“.paintedHaploDiversity”结尾。我想将这些文件合并到一个allOutputs_3.5在父目录中调用的文件中。更具体地说,每个文件包含两行或三行。第一行是我可以忽略的标题。在剩下的一两行中,其中之一具有2第四列中的值。对于每个文件,我想复制2第二列中有 a 的整行,并向其中添加文件名(不包括扩展名“.paintedHaploDiversity”)。我将此文件名称为“simID”。
有关信息,远程计算机在 MAC OS X 10.11.6 (15G22010) 上运行。这是一个简单的桌面。因此不涉及网络(在我的 ssh 命令之外访问远程机器)。
我第一次尝试
for f in *;
do
simID=${f%.paintedHaploDiversity}
awk -v simID=${simID} 'NR>1{if ($4==2) {printf simID"\t"; print}}' $f >> ../allOutputs_3.5
done
Run Code Online (Sandbox Code Playgroud)
但它很慢。我估计需要的时间要几个月甚至几年!然后,我试过了
awk 'FNR==1{simID=substr(FILENAME, 1, length(FILENAME)-22)}FNR>1{if ($4==2) {printf simID"\t"; print}}' * >> ../allOutputs
Run Code Online (Sandbox Code Playgroud)
但它似乎并没有更快。只是作为速度测试,我也考虑过
find . -exec cat '{}' ';' > out
Run Code Online (Sandbox Code Playgroud)
但它又很慢。考虑到问题可能来自正则表达式扩展*,我尝试通过两个 C 样式循环再现每个文件的名称来循环遍历每个文件。
for ((bigID=1; bigID <= 9 ;++bigID)); do
for ((rep=1; rep <= 9000000 ;++rep)); do
awk -v simID=3.5.${bigID}_${rep} 'NR>1{if ($4==2) {printf simID"\t"; print}}' 3.5.${bigID}_${rep}.paintedHaploDiversity >> ../allOutputs_3.5
done
done
Run Code Online (Sandbox Code Playgroud)
这个过程现在快了很多,但仍然需要几个月的时间才能运行!最后,我想,我不妨删除第二列不等于的行2(可能是用sed命令)然后做
for ((bigID=1; bigID <= 6 ;++bigID)); do
for ((r=1; r <= 9000000 ;++r)); do
printf "3.5_${bigID}_${r}\t" >> ../allOutputs_3.5
tail -n +2 3.5_${bigID}_${r}.paintedHaploDiversity >> ../allOutputs_3.5
done
done
Run Code Online (Sandbox Code Playgroud)
现在这个过程预计需要大约两周的时间。这开始是合理的。我仍然想知道是什么导致这个过程如此缓慢以及是否可以改进。
我想瓶颈很可能是磁盘 IO。还是占用大量 CPU 时间的文件系统?该过程是否如此缓慢,因为同一目录中有如此多的文件,并且需要在循环的每次迭代中搜索文件的二叉树?如何改进?我应该尝试用 C++ 编写流程吗?
如果它有帮助,这里是top -o MEM最后一个命令(使用printfand 的命令tail)运行时的输出
Processes: 254 total, 3 running, 12 stuck, 239 sleeping, 1721 threads 03:12:40
Load Avg: 2.04, 1.79, 1.60 CPU usage: 0.84% user, 4.33% sys, 94.81% idle
SharedLibs: 85M resident, 11M data, 10M linkedit.
MemRegions: 42324 total, 4006M resident, 63M private, 230M shared.
PhysMem: 14G used (2286M wired), 10G unused.
VM: 753G vsize, 535M framework vsize, 1206153(0) swapins, 2115303(0) swapouts.
Networks: packets: 413664671/284G in, 126210468/104G out.
Disks: 1539349069/12T read, 1401722156/7876G written.
PID COMMAND %CPU TIME #TH #WQ #PORTS MEM PURG CMPRS PGRP PPID STATE
0 kernel_task 42.1 1716 hrs 167/25 0 2- 1968M 0B 0B 0 0 running
366 SystemUIServ 0.4 24:42:03 5 2 345 1055M 0B 10M 366 1 sleeping
472 softwareupda 0.0 12:46:11 5 0 3760 340M 0B 18M 472 1 sleeping
54242 Sublime Text 0.0 03:55:44 12 0 237 233M 0B 68K 54242 1 sleeping
63 powerd 0.0 44:07:21 2 0 95 204M 0B 8932K 63 1 sleeping
34951 Finder 0.1 04:11:06 9 2 1665 166M 0B 68M 34951 1 sleeping
197 WindowServer 0.0 40:02:58 3 0 453 142M 0B 63M 197 1 sleeping
13248 Terminal 0.0 84:19.45 5 0 388 114M 0B 113M 13248 1 sleeping
29465 X11.bin 0.0 89:38.70 9 0 229 104M 0B 16M 29464 29464 sleeping
12372 system_insta 0.0 00:31.61 2 0 75 78M 0B 9996K 12372 1 sleeping
1588 sysmond 0.0 02:34:04 2 1 23 62M 0B 4536K 1588 1 sleeping
54245 plugin_host 0.0 00:03.88 5 0 56 51M 0B 0B 54242 54242 sleeping
554 spindump 0.0 00:36.51 2 1 164 44M 0B 33M 554 1 sleeping
20024 com.apple.GS 0.0 00:01.43 3 2 24 43M 0B 2200K 20024 1 sleeping
475 suhelperd 0.0 00:19.84 2 0 55 42M 0B 28M 475 1 sleeping
418 installd 0.0 01:21.89 2 0 69 40M 0B 12M 418 1 sleeping
57 fseventsd 0.1 13:03:20 10 0 241 39M 0B 2904K 57 1 sleeping
364 Dock 0.0 08:48.83 3 0 283 38M 0B 27M 364 1 sleeping
201 sandboxd 0.0 18:55.44 2 1 38 38M 0B 10M 201 1 sleeping
103 loginwindow 0.0 04:26.65 2 0 377 35M 0B 3400K 103 1 sleeping
897 systemstatsd 0.0 65:30.17 2 1 43 34M 0B 4928K 897 1 sleeping
367 fontd 0.0 11:35.30 2 0 77 32M 0B 5920K 367 1 sleeping
396 ScopedBookma 0.0 01:00.46 3 2 46 32M 0B 28M 396 1 sleeping
22752 cfbackd 0.4 32:18.73 9 1 84 30M 0B 0B 22752 1 sleeping
39760 Preview 0.0 00:03.75 3 0 209 29M 0B 0B 39760 1 sleeping
53 syslogd 0.0 05:33:59 4 3 186- 29M- 0B 1668K 53 1 sleeping
533 SmartDaemon 0.0 27:07.67 10 7 175 28M 128K 5192K 533 1 stuck
388 iconservices 0.0 00:08.85 2 1 66 27M 0B 157M 388 1 sleeping
7268 diskmanageme 0.0 00:40.14 888 0 8899 27M 0B 7352K 7268 1 sleeping
513 Notification 0.0 00:46.42 3 0 245 26M 0B 9852K 513 1 sleeping
83 opendirector 0.0 19:22:12 6 5 8827 26M 0B 2444K 83 1 sleeping
557 AppleSpell 0.0 03:12.61 2 0 57 26M 0B 10M 557 1 sleeping
422 com.apple.ge 0.0 01:50.41 5 0 83 25M 0B 1680K 422 1 sleeping
397 storeaccount 0.0 00:48.41 4 0 1333 21M 0B 2248K 397 1 sleeping
87 launchservic 0.0 64:26.85 3 2 306 20M 0B 5804K 87 1 sleeping
1 launchd 0.0 26:26:23 5 4 1802 20M 0B 6532K 1 0 stuck
222 taskgated 0.0 17:59:00 3 1 43 19M 0B 4528K 222 1 sleeping
54 UserEventAge 0.0 18:19.74 3 0 32605- 18M- 0B 2968K 54 1 sleeping
4527 com.apple.sp 0.0 00:13.01 2 0 48 17M 0B 7792K 4527 1 sleeping
79 coreduetd 0.0 05:40.06 2 0 95 17M 0B 4604K 79 1 sleepin
Run Code Online (Sandbox Code Playgroud)
这是输出 iostat
disk0 disk1 disk2 cpu load average
KB/t tps MB/s KB/t tps MB/s KB/t tps MB/s us sy id 1m 5m 15m
7.19 152 1.07 8.10 0 0.00 8.22 0 0.00 15 50 35 1.68 1.74 1.59
Run Code Online (Sandbox Code Playgroud)
例子:
考虑以下文件
文件_0:
first second third fourth fifth
bbb a a 2 r
Run Code Online (Sandbox Code Playgroud)
文件_1:
first second third fourth fifth
f o o 2 o
Run Code Online (Sandbox Code Playgroud)
文件_2:
first second third fourth fifth
f r e 1 e
x xxx x 2 x
Run Code Online (Sandbox Code Playgroud)
文件_3:
first second third fourth fifth
a a a 2 a
Run Code Online (Sandbox Code Playgroud)
预期的输出是
file_0 bbb a a 2 r
file_1 f o o 2 o
file_2 x xxx x 2 x
file_3 a a a 2 a
Run Code Online (Sandbox Code Playgroud)
难题。可能会把自己逼到角落里……
如果find命令花费的时间太长,除了打开、读取和关闭每个文件之外什么也不做,那么可能的瓶颈就是 HDD 上的寻道时间。这通常约为 10 毫秒(源代码),因此对于 8100 万个文件,假设每个文件进行一次查找,您要查看的时间大约为 10 天。由于文件系统(目录访问等)的原因,它可能会进行更多的查找,但如果局部性良好,每次查找也可能会更短。
如果您有能力等待这么长时间,我建议您将所有这些文件压缩到一个文件中。这将花费大量时间,但之后您可以更快地处理数据集。
如果无法压缩(或以其他方式复制或访问)每个单独的文件,则解决方案可能是拍摄整个文件系统的映像(快照)并将其复制到更快的驱动器上。SSD 的寻道时间约为 0.1 毫秒(来源),因此使用 SSD 您可以在两个多小时内完成。
更核心的方法是编写直接在原始磁盘字节上操作的代码,实现文件系统的必要部分并使用大型内存缓冲区来避免磁盘寻道。根据文件在磁盘上的分布方式,这可能会给您带来很大的加速,但当然,对此进行编程是一项艰巨的工作。