Уведомления

Группа в Telegram: @pythonsu

#1 Ноя. 26, 2010 23:19:57

Subideal Ox
От:
Зарегистрирован: 2010-11-23
Сообщения: 65
Репутация: +  0  -
Профиль   Отправить e-mail  

Быстрый способ прочитать последнюю строку в файле

виноват =D



Офлайн

#2 Ноя. 26, 2010 23:39:44

Андрей Светлов
От:
Зарегистрирован: 2007-05-15
Сообщения: 3137
Репутация: +  14  -
Профиль   Адрес электронной почты  

Быстрый способ прочитать последнюю строку в файле

=D
Кстати, именно поэтому все перечисленные способы могут не сработать (на utf8 файлах в частности).
Прыгнув в произвольное место, нельзя уверенно установить: ‘\n’ - это переход на новую строчку или часть символа, закодированного несколькими байтами.

Вывод - используйте исключительно ascii в ваших логах :)



Офлайн

#3 Ноя. 27, 2010 00:48:19

Subideal Ox
От:
Зарегистрирован: 2010-11-23
Сообщения: 65
Репутация: +  0  -
Профиль   Отправить e-mail  

Быстрый способ прочитать последнюю строку в файле

Андрей, большое спасибо за твои разъяснения. Все стало на свои места.

С другой стороны, результат работы вполне определен - просто seek работает с байтами, а не с символами, вне зависимости от того, как открыт файл. И никакой магии.Так бы и написали.

К тому же, потенциальные проблемы относится только к произвольному доступу. Если мы просто перебираем файл в обратном порядке, то нам, по большому счету, все равно, в каком режиме он открыт. И мой код будет нормально работать с многобайтными кодировками. Надо только отказаться от предположения, что файл заканчивается переводом строки, а то в случае какого-нибудь “ё” последняя буква сломается - но это детали.

Более того, в коде у doza_end строка может оказаться длиннее MAX_ROW и seek точно также может попасть в середину многобайтного символа (shit happens). То есть сивол выйдет поломанным - тоже мелочь, но неприятно. Соответственно, ‘rb’ в open - это совсем не решение обсуждаемой проблемы.

Еще раз, вывод: документаторам - незачет: понять что они имели ввиду, можно только зная, что они имели ввиду =D

SO



Отредактировано (Ноя. 27, 2010 00:49:45)

Офлайн

#4 Ноя. 27, 2010 00:55:39

Subideal Ox
От:
Зарегистрирован: 2010-11-23
Сообщения: 65
Репутация: +  0  -
Профиль   Отправить e-mail  

Быстрый способ прочитать последнюю строку в файле

Андрей, не прочел твой последний пост, проводил эксперименты над русскими текстами =D

Мой код будет работать даже с китайским ;)
Потому что там нет произвольного доступа, просто перебор с конца - символов или байтов - ему все равно.



Офлайн

#5 Ноя. 27, 2010 02:18:16

Андрей Светлов
От:
Зарегистрирован: 2007-05-15
Сообщения: 3137
Репутация: +  14  -
Профиль   Адрес электронной почты  

Быстрый способ прочитать последнюю строку в файле

А вот это я уже не понимаю.
Мне ясно, почему символы будут пониматься правильно, если читать поток с начала.
И решительно непонятно, как это сделать в общем случае при чтении с конца.
Допустим, в случае с utf-8 все просто - никакой многобайтный символ не сможет содержать внутри ‘\n’.
Для другой кодировки - иные правила. И я не уверен, что у всех кодировок ‘\n’ (байт с кодом 10) не сможет
встретится в середине символа.
Эти китайцы - они такие странные люди, мне мама говорила.

К слову, пробежка по файлу из 25000 строк (взял оочень длинный fb2 на 6 Мб, строки там по абзацу, т.е. тоже весьма большие) - так вот, вычитка всех строк занимает 7 миллисекунд.
На настоящем моем логе на те же 26000 строк (но размером в 1.8 Мб) прочитать все строки занимает 3 миллисекунды.

Стоит ли огород городить?



Офлайн

#6 Ноя. 27, 2010 08:09:23

pyuser
От:
Зарегистрирован: 2007-05-13
Сообщения: 658
Репутация: +  36  -
Профиль   Отправить e-mail  

Быстрый способ прочитать последнюю строку в файле

Андрей Светлов
Кстати, именно поэтому все перечисленные способы могут не сработать (на utf8 файлах в частности).
так и есть, на файлах в кодировке utf-8 - не работает (ось - windows). т.е. открывать нужно только в бинарном режиме. (я это еще в прошлом веке усвоил :))



Офлайн

#7 Ноя. 27, 2010 08:46:49

doza_and
От:
Зарегистрирован: 2010-08-15
Сообщения: 4138
Репутация: +  253  -
Профиль   Отправить e-mail  

Быстрый способ прочитать последнюю строку в файле

Более того, в коде у doza_end строка может оказаться длиннее MAX_ROW и seek точно также может попасть в середину многобайтного символа (shit happens). То есть сивол выйдет поломанным - тоже мелочь, но неприятно. Соответственно, ‘rb’ в open - это совсем не решение обсуждаемой проблемы
Я что-то не понял. Первая часть предложения - по поводу строка окажется длиннее. Она не окажется в силу заявленного ограничения (которое можно установить при записи лога). Но по-моему это не имеет отношения к делу.
Вторая половина предложения. Символ окажется поломанным. Запросто. Для работы алгоритма важно только чтобы ‘\n’ в двоичном потоке был валидным разделителем (те в имеющихся сообщениях не было внутри этого символа что конечно не всегда можно гарантировать). но если это так, то после разбиения строка правильно разрежется с нужным выравниванием (как мне кажется я это не проверял).

Стоит ли огород городить?
Как всегда зависит от задачи. У нас есть такая штука логи полномасштабного тренажера. За рабочий день 4-5 часов набирается 1-3 гигабайта. Довольно часто надо последнюю тысячу сообщений загрузить после некоторого момента времени. В этом случае может довольно сильно подтормаживать.

Еще одно замечание по поводу чтения взад. Сия процедура сильно зависит от стратегии кеширования операционкой данных получаемых из файла. Его можно открыть с различными стратегиями оптимизации доступа. Обычно кешируются 4-8 килобайтные блоки на чтение вперед. Если вы будете seekaться назад это сильно снизит скорость обмена. Может раз в 100 снизить скорость. Поэтому уважаемый Андрей прав - смешные файлы в 25000 строк проще целиком заглотить чтением вперед(предположение о малом размере лога). И писанины меньше будет.



Отредактировано (Ноя. 27, 2010 08:49:59)

Офлайн

#8 Ноя. 27, 2010 08:58:49

Андрей Светлов
От:
Зарегистрирован: 2007-05-15
Сообщения: 3137
Репутация: +  14  -
Профиль   Адрес электронной почты  

Быстрый способ прочитать последнюю строку в файле

Для гигабайтных логов я, наверное, строил бы индекс. Например, с секундными отметками.
А затем, быстро прыгнув на ближайшее время в индексе - снова прокрутил бы вперед до нужной записи.
Программы - это не только быстрые алгоритмы но и оптимальные структуры данных :)

P.S. А откуда информация о 4-8 Кб кеше? Допускаю, что у stdio размер буфера примерно такой. Но у дисковой подсистемы буфер должен быть изрядно побольше, думаю. Плюс к тому же многомегабайтные кеши у собственно жестких дисков.
И вся эта машинерия должна быть оптимизирована на упреждающее чтение - единственно годная стратегия в общем случае.



Офлайн

#9 Ноя. 27, 2010 09:16:23

doza_and
От:
Зарегистрирован: 2010-08-15
Сообщения: 4138
Репутация: +  253  -
Профиль   Отправить e-mail  

Быстрый способ прочитать последнюю строку в файле

А мы так и делаем (трехуровневый индекс поскольку эта гадость иногда дня по 4 круглосуточно пашет) :). Блоки нижнего уровня грузятся целиком.

Файл большой 15 - 20 кк строк.
Короче - не один вариант не подходит.
:)
Люди спросили я ответил. Код чтения с конца действительно получился страшный.



Офлайн

#10 Ноя. 27, 2010 09:31:02

doza_and
От:
Зарегистрирован: 2010-08-15
Сообщения: 4138
Репутация: +  253  -
Профиль   Отправить e-mail  

Быстрый способ прочитать последнюю строку в файле

По поводу кэша. Я наверное неясно написал. Извините. Я писал, что операционка на уровне ядра оперирует кусками (блоками ) по 4-8к, но не то что весь кэш такого размера. Информация - слухи :). Я говорил с человеком который у нас исследовал этот вопрос для винды и нескольких клонов linux. Его методки-какое-то страшное ковыряние отладчиком в ядре с моей точки зрения - магия. Вопрос был про ток как raid влияет на скорость. По поводу размера буферов вы правы - десятки мегабайт. Вы мне кажется правы все это заточено на упреждающее чтение вперед.

Люди могут попробовать например почитать большой файл (мегов 100) вперед и поделать по нему random seek в питоне. У меня получалось что обмен винчестером как и положено десятки мегабайт в секунду на на каждый seek надо 0.01 сек



Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version