大文件读写效率比较

之前做到一个大日志文件(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处理大文本文件的时候需要综合考虑服务器内存,文件处理次数来决定使用哪种方式。

posted @ 2017-05-12 14:19  苏小北1024  阅读(2993)  评论(0编辑  收藏  举报