大文件讀寫效率比較


之前做到一個大日志文件(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處理大文本文件的時候需要綜合考慮服務器內存,文件處理次數來決定使用哪種方式。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM