python - 为什么 Python 3.3 中的打印速度如此之慢,我该如何解决?

标签 python performance unicode python-3.3

我刚刚尝试用 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 <frozen importlib._bootstrap>: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(<module>)
        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(<module>)
        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 到字节的转换,反之亦然。

在您的情况下,您可能想绕过它并只处理字节;您可以通过 .buffer attribute 访问底层的 BufferedIOBase 实现:

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() 现在使用 bytes 文字 b'"' 而我们编写一个字节文字 b'\n'(通常由 print() 处理)。

以上与 Python 2.6 及更高版本兼容。 Python 2.5 不支持 b 前缀。

关于python - 为什么 Python 3.3 中的打印速度如此之慢,我该如何解决?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20584047/

相关文章:

java - 如何指定 Java 源文件的编码?

C++ 文件读取库 - ANSI 和 Unicode

python - 如何防止将字符串分解为字符列表?

python - 为什么我不能在 Python PIL 中裁剪此图像? (简单的语法问题?)

python - 仅解码 URL 非 ascii 字符

python - 高效地多处理并发 python 脚本

sql-server - SQL 查询中的累积列

performance - Powershell 脚本的速度。寻求优化

python - Pandas:找到跨列的共同值

bash - BASH 变量名称中可以接受哪些 Unicode 符号?