2013-12-14 5 views
14

私はPython 3.3でこのスクリプトを実行しようとしました。 残念ながら、それはPython 2.7より約2倍遅いです。ここでなぜPython 3.3で印刷が遅くなり、どうすれば修正できますか?

#!/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と関係がありますか?

+3

さて、 'print'はpython3ではもう文ではありませんので、いくらかのオーバーヘッドが予想されます。これはおそらく 'sys.stdout.write'を使うか、あるいはメモリの問題ではないことを前提として、文字列のリストを作成してから' sys.stdout.writelines'を使うことで、もっと少なくなります。どちらの場合でも、 'print'で作成した改行を自分で追加する必要があります。 – l4mpi

答えて

12

Python 3は、stdinから読み取られたデータをデコードし、stdoutに再度エンコードします。 print()関数の方がユニコードからバイトへの変換の方が遅く、逆も同様です。

あなたの場合は、おそらくこれをバイパスして、バイトだけを処理したいと思うかもしれません。あなたは.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() 

あなたは今stdoutTextIOBase実装への書き込みを主張しているstdout.write()print()として使用するを持っています。バイトリテラル(通常print()によって考慮されるであろう)、ならびにb'\n'.split()は現在バイトリテラルb'"'を使用して、我々は書き込み

注意。

上記はPython 2.6以降と互換性があります。 Python 2.5では、接頭辞bはサポートされていません。

関連する問題