为什么Python 3.3中的打印速度如此之慢?如何解决?

 西门庆重生727 发布于 2023-02-10 14:18

我只是尝试用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有关吗?

1 个回答
  • 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前缀.

    2023-02-10 14:23 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有