前面的一篇文章关注的是Python str的拼接效率,其实bytes的拼接原理和str类似。现在继续关注另外一个bytes比str多出来的特性bytearray,bytearray最突出的特点就是可以被修改,这是str无法办到的,这也意味着bytearray在传输大量数据时,可以免去一些数据copy,提升CPU和RAM利用率,尤其在网络IO时很有用。
测试环境:Mac OS X 10.9,Python 3.3
测试文件:完整HTML文档,约4.9MB
下文运行三个case来对比bytes与bytearray的效率问题:
1. 基准。将完整测试文件读入io.BytesIO,后面的#2和#3将基于io.BytesIO进行,便于观察bytes与bytearray带来的直接影响。
2. bytes读取。通过file.read方式读取io.BytesIO,每次返回的都是一个新bytes对象。
2. bytearray读取。通过file.readinto方式读取io.BytesIO,每次都将内容写入到一个预先分配的bytearray对象。
完整源码
-
import argparse
-
from functools import reduce
-
import io
-
import os
-
-
PAGESIZE = os.sysconf('SC_PAGESIZE')
-
-
def run_case1(fp):
-
"""基准"""
-
with fp.getbuffer() as view:
-
pass
-
-
def run_case2(fp):
-
"""btyes读取"""
-
while True:
-
blk = fp.read(PAGESIZE)
-
if not blk:
-
break
-
-
def run_case3(fp):
-
"""bytearray读取"""
-
blk = bytearray(PAGESIZE)
-
while True:
-
if fp.readinto(blk) <= 0:
-
break
-
-
def collect_rusage(fp, count, proc):
-
for i in range(count):
-
fp.seek(0)
-
if os.fork() == 0:
-
proc(fp)
-
os._exit(os.EX_OK)
-
pid, status, rusage = os.wait3(os.WEXITED)
-
yield rusage.ru_utime, rusage.ru_stime, rusage.ru_maxrss
-
-
def main():
-
parser = argparse.ArgumentParser(description='Python bytes')
-
parser.add_argument('infile', type=argparse.FileType('rb'),
-
help='binary source')
-
parser.add_argument('-c', '--count', type=int,
-
help='loop count for each case')
-
args = parser.parse_args()
-
memfile = io.BytesIO(args.infile.read())
-
-
# main logic begins
-
testcases = [run_case1, run_case2, run_case3]
-
for case in testcases:
-
collector = list(collect_rusage(memfile, args.count, case))
-
avg_utime, avg_stime, avg_maxrss = \
-
map(lambda x: x/len(collector),
-
reduce(lambda x, y: (m+n for m, n in zip(x, y)), collector))
-
print('{} utime: {:.06f}, stime: {:.06f}, maxrss: {}'.format(
-
case.__doc__, avg_utime, avg_stime, int(avg_maxrss)))
-
-
if __name__ == '__main__':
-
main()
执行三次,每次执行中,每个case都会运行100次取均值
-
bash-3.2 $python bytesio.py The\ GNU\ C\ Library.html -c 100
-
基准 utime: 0.000143, stime: 0.000205, maxrss: 761446
-
btyes读取 utime: 0.001460, stime: 0.000916, maxrss: 5853880
-
bytearray读取 utime: 0.001223, stime: 0.000922, maxrss: 5878210
-
-
bash-3.2 $python bytesio.py The\ GNU\ C\ Library.html -c 100
-
基准 utime: 0.000144, stime: 0.000202, maxrss: 767672
-
btyes读取 utime: 0.001451, stime: 0.000930, maxrss: 5861130
-
bytearray读取 utime: 0.001216, stime: 0.000913, maxrss: 5886238
-
-
bash-3.2 $python bytesio.py The\ GNU\ C\ Library.html -c 100
-
基准 utime: 0.000145, stime: 0.000206, maxrss: 756817
-
btyes读取 utime: 0.001444, stime: 0.000925, maxrss: 5855764
-
bytearray读取 utime: 0.001204, stime: 0.000901, maxrss: 5883535
最后分析结果,其实还是有与我预期不一致的地方,还好在可理解的范围内:
1. CPU。系统CPU相差无几,但bytes用户CPU超过bytearray约20%,这在实践中是一个不可忽略的差距。
2. RAM。竟然相差无几,莫非新建的bytes对象内存都重用了?只能归功于Python heap manager了。。。
阅读(8116) | 评论(0) | 转发(0) |