之前做到一個大日志文件(size > 1G)解析的項目,在此記錄下對於大文本解析方式的效率比較。不同方式的性能差別很大,那個項目的日志解析時間能從原來的超過36小時優化到只需要2分鍾,awk功不可沒。
bash 比較
bash腳本中對於文本的讀取主要有以下四種,盡管 AWK 具有完全屬於其本身的語法,但在此我也把它歸在一起:
#方法一
func1(){
rm -f $2
echo "$(date) start to read"
start_time=$(date +%s)
cat $1|while read Line
do
echo $Line >> $2
done
end_time=$(date +%s)
echo "$(date) end to read"
echo "cost: "$((end_time-start_time))"sec"
}
#方法二
func2(){
rm -f $2
echo "$(date) start to read"
start_time=$(date +%s)
while read Line
do
echo $Line >> $2
done <$1
end_time=$(date +%s)
echo "$(date) end to read"
echo "cost: "$((end_time-start_time))"sec"
}
#方法三
func3(){
rm -f $2
echo "$(date) start to read"
start_time=$(date +%s)
for Line in `cat $1`
do
echo $Line >> $2
done
end_time=$(date +%s)
echo "$(date) end to read"
echo "cost: "$((end_time-start_time))"sec"
}
#func4
func4(){
rm -f $2
echo "$(date) start to read"
start_time=$(date +%s)
awk '{print $0}' $1 > $2
echo "$(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 Timer
t1=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處理大文本文件的時候需要綜合考慮服務器內存,文件處理次數來決定使用哪種方式。