Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Bash 合并数百万个文件的最快方法_Bash_Performance_File_Merge_Disk Io - Fatal编程技术网

Bash 合并数百万个文件的最快方法

Bash 合并数百万个文件的最快方法,bash,performance,file,merge,disk-io,Bash,Performance,File,Merge,Disk Io,远程计算机上有8100万个文件(!)存储在一个目录中。所有文件都以“.paintedHaploDiversity”结尾。我想将这些文件合并到父目录中名为alloutput_3.5的文件中。更具体地说,每个文件包含两行或三行。第一行是我可以忽略的标题。在剩下的一行或两行中,有一行在第四列中具有值2。对于每个文件,我希望复制第二列中有2的整行,并将文件名添加到其中(不包括扩展名“.paintedHaploDiversity”)。我将此文件名称为“simID” 有关信息,远程计算机在MAC OS X

远程计算机上有8100万个文件(!)存储在一个目录中。所有文件都以“.paintedHaploDiversity”结尾。我想将这些文件合并到父目录中名为
alloutput_3.5
的文件中。更具体地说,每个文件包含两行或三行。第一行是我可以忽略的标题。在剩下的一行或两行中,有一行在第四列中具有值
2
。对于每个文件,我希望复制第二列中有
2
的整行,并将文件名添加到其中(不包括扩展名“.paintedHaploDiversity”)。我将此文件名称为“simID”

有关信息,远程计算机在MAC OS X 10.11.6(15G22010)上运行。这是一个简单的destkop。因此,不涉及任何网络(除了我的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
但是速度很慢。我估计所需的时间要几个月甚至几年!然后,我试着

awk 'FNR==1{simID=substr(FILENAME, 1, length(FILENAME)-22)}FNR>1{if ($4==2) {printf simID"\t"; print}}' * >> ../allOutputs
但它似乎并没有更快。作为速度测试,我还考虑了

find . -exec cat '{}' ';' > out
但它又是非常缓慢的。考虑到问题可能来自正则表达式扩展
*
,我试图通过两个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
这一过程现在预计需要大约两周的时间。这开始是合理的。我仍然想知道是什么原因导致这一进程如此缓慢,是否可以改进

我想瓶颈可能是磁盘IO。还是需要大量CPU时间的文件系统?是因为同一目录中有这么多文件,并且在循环的每次迭代中都需要搜索文件的二叉树,所以这个过程会这么慢吗?如何改进?我应该试着用C++编写这个过程吗? 如果有帮助的话,在最后一个命令(使用
printf
tail
的命令)运行时,输出
top-o MEM

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
这是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

例如:

考虑以下文件

文件0:

first second third fourth fifth
bbb a a 2 r
文件1:

first second third fourth fifth
f o o 2 o
文件2:

first second third fourth fifth
f r e 1 e
x xxx x 2 x
文件3:

first second third fourth fifth
a a a 2 a
预期产量为

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

难题。可能把你自己画到了一个角落里

如果即使是
find
命令花费的时间太长,除了打开、读取和关闭每个文件之外什么也不做,那么可能的瓶颈就是硬盘上的寻道时间。这通常约为10毫秒(),因此假设每个文件有一次搜索,那么对于8100万个文件,您将在大约10天内查看。由于文件系统(目录访问等)的原因,可能会有更多的寻道,但如果局部性好,每个寻道也可能更短

如果你能等这么久,我建议你把所有这些文件压缩成一个文件。这将花费很多时间,但之后您可以更快地处理数据集

如果压缩(或复制或访问)每个单独的文件是不可能的,那么解决方案可能是拍摄整个文件系统的映像(快照),并将其复制到更快的驱动器上。SSD的寻道时间约为0.1毫秒(),因此使用SSD只需两个多小时即可完成


更为核心的方法是编写直接在原始磁盘字节上运行的代码,实现文件系统的必要部分,并使用大内存缓冲区来避免磁盘查找。根据文件在磁盘上的分散方式,这可能会给您带来很大的加速,但当然,编写此程序是一项不平凡的工作。

您可能可以处理对程序
grep
sed
的两个单独调用。这应该很快。也许比自编的C程序还要快

cd dir_with_all_the_files
grep -rE '^([^ ]+ +){3}2 ' . | 
sed -En 's/^\.\/(.*)\.paintedHaploDiversity:/\1 /p' > ../allOutputs_3.5
作出的假设:

  • 要搜索的列的标题也不是
    2
  • 该目录不包含子目录。
    该命令仍可能产生正确的结果,但必须运行不必要的时间
  • 文件名不包含
    或换行符
  • 您的
    grep
    实现支持非Posix
    -r
    选项(通常情况下)
如果您的
grep
实施支持进一步改进:

  • 添加
    -m1
    以加快搜索速度
  • 请尝试
    grep-P
    (Mac OS通常不支持)或
    pcregrep
    。PCRE有时更快。使用PCRE,您还可以尝试使用可选的regex
    '^(.*?{3}2'
  • --exclude dir\*
    (注意,
    *
    被引用)排除子目录,因此即使没有上述假设,您也可以使用该命令
如果希望按文件名对输出进行排序(就像迭代
*.paintedhaplodivity
时得到的那样),请在之后运行
sort-t'-k 1,1-o alloutput_3.5{,}


您不妨设置
export LC_ALL=C
以加快
grep
排序
,甚至
sed
,除了处理几GB数据的明显I/O负载之外,问题是启动一个或多个进程需要花费8100万次的时间。即使创建命令行或将文件全局扩展到300MB(
表示*.
)也可能需要大量时间或超出系统和程序规范

一种解决方案是编写一个C程序来打开文件并对其进行处理,或者将其内容传递给其他程序。但这可能需要几天来编程和调试,也许你的实习生正在休假。但是Unix工具箱中已经有一些程序可以完成您所需的部分工作,只是文件名丢失了。我们假设所有文件都在一个名为bla的目录中

使用tar创建包含文件内容的流,如下所示:

tar cf-bla | tar-xOf-

默认情况下,这会将文件的连接内容写入控制台的标准输出。TAR和grep都只是
cd dir_with_all_the_files
grep -rE '^([^ ]+ +){3}2 ' . | 
sed -En 's/^\.\/(.*)\.paintedHaploDiversity:/\1 /p' > ../allOutputs_3.5
for bigID in {1..6}
do
    # poll first 99 files (r=1..99) + 9 millionth file

    awk 'FNR==1{simID=substr(FILENAME, 1, length(FILENAME)-22)}FNR>1{if ($4==2) {printf simID"\t"; print}}' 3.5_${bigID}_{1..99}.paintedHaploDiversity 3.5_${bigID}_9000000.paintedHaploDiversity >> ../allOutputs

    # break rest of files into ~10K chunks based on first 3 digits of suffix

    for r in {100..899}      # break 9000000 into ~10K chunks
    do
        awk 'FNR==1{simID=substr(FILENAME, 1, length(FILENAME)-22)}FNR>1{if ($4==2) {printf simID"\t"; print}}' 3.5_${bigID}_${r}*.paintedHaploDiversity >> ../allOutputs
    done
done
find . -type f -printf "%f\n" |\
xargs awk '$4==2{ print(substr(FILENAME, 1, length(FILENAME)-22), $0) }' >> output.txt
for (( i=1;i<=9;i++ )); do
   for (( j=1;j<=9000000;j++ )); do
      printf "file_%s_%s\n" "$i" "$j" >> filenames.txt
   done
done
cat filenames.txt | xargs awk '{...}'
split -l 1000000 -d filenames.txt chunk
for f in chunk*; do cat "$f" | xargs awk '{...}' ; done