Ich habe gerade versucht, dieses Skript mit Python 3.3 auszuführen. Leider ist es etwa doppelt so langsam wie mit Python 2.7.Warum ist Drucken in Python 3.3 so langsam und wie kann ich es beheben?
#!/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()
Hier sind die Ergebnisse:
$ 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
Profilieren zeigt, dass die zusätzliche Zeit im Druck verbringen ist:
$ 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}
Wie kann ich diesen Aufwand vermeiden? Hat es etwas mit UTF-8 zu tun?
Nun, 'print' ist in python3 kein Statement mehr, daher wird ein Overhead erwartet. Dies könnte wahrscheinlich durch Verwendung von 'sys.stdout.write' reduziert werden - oder besser noch, indem Sie zuerst eine Liste Ihrer Strings erstellen und dann' sys.stdout.writelines' verwenden, vorausgesetzt, dass Speicher kein Problem ist. In beiden Fällen müssten Sie die von 'print' erstellten Zeilenumbrüche selbst hinzufügen. – l4mpi