Мне приходилось публиковать это на похожем вопросе, пока оценка моей репутации немного не подскочила (спасибо тому, кто ударил меня!).
Все эти решения игнорируют один способ сделать это значительно быстрее, а именно, используя небуферизованный (необработанный) интерфейс, используя байтовые массивы и выполняя собственную буферизацию. (Это применимо только в Python 3. В Python 2 необработанный интерфейс может или не может использоваться по умолчанию, но в Python 3 вы по умолчанию будете использовать Unicode.)
Используя модифицированную версию инструмента синхронизации, я считаю, что следующий код работает быстрее (и немного более питонно), чем любое из предложенных решений:
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
Используя отдельную функцию генератора, она быстрее запускается:
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 )
Это можно сделать полностью с помощью встроенных выражений генераторов, используя itertools, но это выглядит довольно странно:
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 )
Вот мои сроки:
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