之前做到一個大日志文件(size > 1G)解析的項目,在此記錄下對于大文本解析方式的效率比較。不同方式的性能差別很大,那個項目的日志解析時間能從原來的超過36小時優化到只需要2分鐘,awk功不可沒。
bash 比較
bash腳本中對于文本的讀取主要有以下四種,盡管 AWK 具有完全屬于其本身的語法,但在此我也把它歸在一起:
#方法一
func1(){rm -f $2echo "$(date) start to read"start_time=$(date +%s)cat $1|while read Linedoecho $Line >> $2doneend_time=$(date +%s)echo "$(date) end to read"echo "cost: "$((end_time-start_time))"sec"
}#方法二
func2(){rm -f $2echo "$(date) start to read"start_time=$(date +%s)while read Linedoecho $Line >> $2done <$1end_time=$(date +%s)echo "$(date) end to read"echo "cost: "$((end_time-start_time))"sec"
}#方法三
func3(){rm -f $2echo "$(date) start to read"start_time=$(date +%s)for Line in `cat $1`doecho $Line >> $2doneend_time=$(date +%s)echo "$(date) end to read"echo "cost: "$((end_time-start_time))"sec"
}#func4
func4(){rm -f $2echo "$(date) start to read"start_time=$(date +%s)awk '{print $0}' $1 > $2echo "$(date) end to read"echo "cost: "$((end_time-start_time))"sec"
}source=$1
dest=$2#比較結果:
echo "####cat read: "
func1 $source $dest
echo "####redirect read: "
func2 $source $dest
echo "####for read: "
func3 $source $dest
echo "####awk read: "
func4 $source $dest
結果:
cat read:
Thu Jan 15 07:57:50 GMT 2015 start to read
Thu Jan 15 07:58:33 GMT 2015 end to read
cost: 43sec
redirect read:
Thu Jan 15 07:58:33 GMT 2015 start to read
Thu Jan 15 07:59:01 GMT 2015 end to read
cost: 28sec
for read:
Thu Jan 15 07:59:01 GMT 2015 start to read
Thu Jan 15 08:00:00 GMT 2015 end to read
cost: 59sec
awk read:
Thu Jan 15 08:00:00 GMT 2015 start to read
Thu Jan 15 08:00:00 GMT 2015 end to read
cost: 0sec
從以上結果可以看出,awk的效率遠超其他方法
python 比較
python 有三種讀取文件的方法:
read() 會將所有內容讀入到一個字符串中
readline() 每次讀取一行
readlines() 將所有內容按行讀取,返回一個列表,列表中每個元素是一個字符串,一個字符串是一行內容
所以從效率上講, read() 和readlines()會比readline()高,但是同時對內存的要求也比較高,需要能一次性將文件內容放入內存中。但是如果這個文件很大的話,就會影響到程序運行的速度,甚至會導致程序掛掉,此時分行讀取或是設置buff_size會是個更好的選擇
#!/usr/bin/env python
import time
import os
def func1(source,dest):os.remove(dest)with open(source, 'r') as fr:content=fr.read()with open(dest,'w') as fw:fw.write(content)
def func2(source,dest):os.remove(dest)fw=open(dest,'w')for line in open(source,'r'):fw.write(line)fw.close
if __name__ == '__main__':from timeit import Timert1=Timer("func1('log','log1')","from __main__ import func1")t2=Timer("func2('log','log1')","from __main__ import func2")print "read once: "+str(t1.timeit(1))print "read line: "+str(t2.timeit(1))
40M文件5次處理時間:
read once: 0.308089971542
read line: 1.17492413521
1G文件首次處理時間:
read once: 8.17146706581
read line: 4.13687205315
1G文件5次處理時間:
read once: 7.32681894302
read line: 30.3610920906
有意思的是,雖然一次性讀入內存效率比line by line讀取的效率差,但是假如重復處理同一個文件,一次性讀取的總體效率反而高,所以python應該做了類似于緩存的機制。所以當我們用python處理大文本文件的時候需要綜合考慮服務器內存,文件處理次數來決定使用哪種方式。