Musiałem napisać to na podobne pytanie, dopóki moja ocena reputacji nieco nie podskoczyła (dzięki temu, kto mnie uderzył!).
Wszystkie te rozwiązania ignorują jeden ze sposobów na przyspieszenie tego działania, a mianowicie użycie niebuforowanego (surowego) interfejsu, używanie bajtów i tworzenie własnego bufora. (Dotyczy to tylko Pythona 3. W Pythonie 2 domyślny interfejs może, ale nie musi być używany, ale w Pythonie 3 domyślnie zostanie ustawiony Unicode.)
Korzystając ze zmodyfikowanej wersji narzędzia do pomiaru czasu, uważam, że następujący kod jest szybszy (i nieznacznie bardziej pythoniczny) niż którekolwiek z oferowanych rozwiązań:
def rawcount(filename):
f = open(filename, 'rb')
lines = 0
buf_size = 1024 * 1024
read_f = f.raw.read
buf = read_f(buf_size)
while buf:
lines += buf.count(b'\n')
buf = read_f(buf_size)
return lines
Korzystanie z osobnej funkcji generatora przyspiesza smidge:
def _make_gen(reader):
b = reader(1024 * 1024)
while b:
yield b
b = reader(1024*1024)
def rawgencount(filename):
f = open(filename, 'rb')
f_gen = _make_gen(f.raw.read)
return sum( buf.count(b'\n') for buf in f_gen )
Można to zrobić całkowicie za pomocą wyrażeń generatorów wbudowanych za pomocą itertools, ale robi się dość dziwnie:
from itertools import (takewhile,repeat)
def rawincount(filename):
f = open(filename, 'rb')
bufgen = takewhile(lambda x: x, (f.raw.read(1024*1024) for _ in repeat(None)))
return sum( buf.count(b'\n') for buf in bufgen )
Oto moje czasy:
function average, s min, s ratio
rawincount 0.0043 0.0041 1.00
rawgencount 0.0044 0.0042 1.01
rawcount 0.0048 0.0045 1.09
bufcount 0.008 0.0068 1.64
wccount 0.01 0.0097 2.35
itercount 0.014 0.014 3.41
opcount 0.02 0.02 4.83
kylecount 0.021 0.021 5.05
simplecount 0.022 0.022 5.25
mapcount 0.037 0.031 7.46