我有一个数据导入脚本,可以读取行并将它们添加到数据库,非常好。 不幸的是,脚本(或其运行时或数据库库或其他)中的某些内存泄漏,大量导入使用单调增加的主内存,导致交换缓慢,然后耗尽内存过程死亡。 将import分成多个运行是一个解决方法; 我一直在做split
然后在每一块做一个循环的执行导入脚本。
但我宁愿跳过制作分割文件,这感觉应该是一个单线程。 实际上,似乎应该有一个相当于xargs
的行,而不是作为parameter passing给stdin上的指定命令。 如果这个假设的命令是xlines
,那么我期望以下内容为myimport
每批最多50,000行运行myimport
脚本:
cat giantfile.txt | xlines -L 50000 myimport
我错过了一些其他名称下的xlines
likefunction,或隐藏在其他命令的选项中? 或者可以在几行BASH脚本中完成xlines
?
使用GNU并行 – 在这里可用。
您将需要--pipe
选项以及--block
选项(这需要一个字节大小,而不是行数)。
有些东西是:
cat giantfile.txt | parallel -j 8 --pipe --block 4000000 myimport
(这是选择50,000行的块大小* 80字节= 4000000,这里也可以缩写为4m
)。
如果您不希望作业实际上并行运行,请将8
更改为1
。 或者,您可以将其完全保留,并且每个CPU核心将运行一个作业。
你也可以通过跑步来避开cat
parallel ... < giantfile.txt
将以下代码保存为test.sh脚本。
#!/bin/bash tempFile=/tmp/yourtempfile.temp rm -f tempFile > /dev/null 2>&1 declare -i cnt=0 while read line do cnt=$(($cnt+1)) if [[ $cnt < $1 || $cnt == $1 ]]; then echo $line >> tempFile else echo $line >> tempFile cat tempFile | myimport rm -f tempFile > /dev/null 2>&1 cnt=$((0)) fi done < $2 exit 0
然后运行./test.sh 500000 giantfile.txt
。 我使用tempFile来保存指定数量的行,然后使用您的导入脚本处理它。 我希望它有帮助。
我的方法,没有安装parallel
,也没有写入临时文件:
#!/bin/bash [ ! -f "$1" ] && echo "missing file." && exit 1 command="$(which cat)" # just as example, insert your command here totalSize="$(wc -l $1 | cut -f 1 -d ' ')" chunkSize=3 # just for the demo, set to 50000 in your version offset=1 while [ $[ $totalSize + 1 ] -gt $offset ]; do tail -n +$offset $1 | head -n $chunkSize | $command let "offset = $offset + $chunkSize" echo "----" done
测试:
seq 1000 1010 > testfile.txt ./splitter.sh testfile.txt
输出:
1000 1001 1002 ---- 1003 1004 1005 ---- 1006 1007 1008 ---- 1009 1010 ----
这样,解决方案仍然是可移植的,性能比临时文件更好。