我只是尝试用Python 3.3运行这个脚本.不幸的是,它的速度比使用Python 2.7快两倍.
#!/usr/bin/env python from sys import stdin def main(): for line in stdin: try: fields = line.split('"', 6) print(fields[5]) except: pass if __name__ == '__main__': main()
结果如下:
$ time zcat access.log.gz | python3 -m cProfile ./ua.py > /dev/null real 0m13.276s user 0m18.977s sys 0m0.484s $ time zcat access.log.gz | python2 -m cProfile ./ua.py > /dev/null real 0m6.139s user 0m11.693s sys 0m0.408s
分析显示额外的时间花在打印上:
$ zcat access.log.gz | python3 -m cProfile ./ua.py | tail -15 Ordered by: standard name ncalls tottime percall cumtime percall filename:lineno(function) 1 0.000 0.000 0.000 0.000:1594(_handle_fromlist) 196806 0.234 0.000 0.545 0.000 codecs.py:298(decode) 1 0.000 0.000 13.598 13.598 ua.py:3( ) 1 4.838 4.838 13.598 13.598 ua.py:6(main) 1 0.000 0.000 13.598 13.598 {built-in method exec} 1 0.000 0.000 0.000 0.000 {built-in method hasattr} 4300456 4.726 0.000 4.726 0.000 {built-in method print} 196806 0.312 0.000 0.312 0.000 {built-in method utf_8_decode} 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects} 4300456 3.489 0.000 3.489 0.000 {method 'split' of 'str' objects} $ zcat access.log.gz | python2 -m cProfile ./ua.py | tail -10 Ordered by: standard name ncalls tottime percall cumtime percall filename:lineno(function) 1 0.000 0.000 6.573 6.573 ua.py:3( ) 1 3.894 3.894 6.573 6.573 ua.py:6(main) 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects} 4300456 2.680 0.000 2.680 0.000 {method 'split' of 'str' objects}
我怎样才能避免这种开销?它与UTF-8有关吗?
Python 3解码从中读取的数据stdin
并再次编码为stdout
; print()
与unicode-to-bytes转换相比,这里的函数并不是那么慢,反之亦然.
在你的情况下,你可能想绕过这个并只处理字节; 您可以BufferedIOBase
通过以下.buffer
属性访问底层实现:
from sys import stdin, stdout try: bytes_stdin, bytes_stdout = stdin.buffer, stdout.buffer except AttributeError: bytes_stdin, bytes_stdout = stdin, stdout def main(): for line in bytes_stdin: try: fields = line.split(b'"', 6) bytes_stdout.write(fields[5] + b'\n') except IndexError: pass if __name__ == '__main__': main()
现在,您必须使用stdout.write()
如print()
上写入坚持stdout
TextIOBase
执行.
请注意,.split()
现在使用字节文字b'"'
,我们也写了一个字节文字b'\n'
(通常会由它来处理print()
).
以上与Python 2.6及更高版本兼容.Python 2.5不支持b
前缀.