Уведомления

Группа в Telegram: @pythonsu

#1 Июль 14, 2015 21:53:54

neitro
Зарегистрирован: 2015-03-13
Сообщения: 25
Репутация: +  0  -
Профиль   Отправить e-mail  

Проблема с алгоритмом чтения данных из файла

Здравствуйте, ув форумчане!
Задачка следующая:
имеется файл (файл достаточно большой ~ 1 000 000 строк)
В каждой строке имеется id (причем не численный, а символьный вида ‘65s4dfg’) + другая информация, разделенная символом ‘;’
Делается выборка из ~5 000 id.
Результат обрабатывается на vps с не очень большим запасом оперативы.

Соответственно алгоритм работ следующий:
для каждого id выполняем поиск по строкам в виде
f=open('file.csv','r')
for line in f:
if id in line: (действие)

Все работает достаточно долго (даже прогресс бар сделал что бы отследить ситуацию) ~20 мин за круг.
Конечно можно все загрузить в оперативу (а если файл разрастется в 2-5-10-50-100-1000-n раз)
Какие есть варианты кроме построчного чтения строк?

Офлайн

#2 Июль 14, 2015 23:57:07

JOHN_16
От: Россия, Петропавловск-Камчатск
Зарегистрирован: 2010-03-22
Сообщения: 3292
Репутация: +  221  -
Профиль   Отправить e-mail  

Проблема с алгоритмом чтения данных из файла

читать кусок файла ( буфер ) в память и его обрабатывать там. Но это только в том случае если действительно это проблемное место. Иначе выигрыша не дает.



_________________________________________________________________________________
полезный блог о python john16blog.blogspot.com

Офлайн

#3 Июль 15, 2015 00:01:01

Budulianin
От:
Зарегистрирован: 2011-10-18
Сообщения: 1218
Репутация: +  33  -
Профиль   Отправить e-mail  

Проблема с алгоритмом чтения данных из файла

Код в теги.

neitro
Результат обрабатывается на vps с не очень большим запасом оперативы.
На память тут нагрузки вообще не будет, благодаря итератору.

neitro
f=open('file.csv','r')
for line in f:
if id in line: (действие)

Посмотри, как работать с файлами через оператор контекста.

neitro
Конечно можно все загрузить в оперативу (а если файл разрастется в 2-5-10-50-100-1000-n раз)
Грузи, ничего не изменится.

neitro
Какие есть варианты кроме построчного чтения строк?
Предварительно разбить файл на части и обработать их параллельно, 1 процесс на ядро процессора.



Офлайн

#4 Июль 15, 2015 00:10:30

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 10016
Репутация: +  857  -
Профиль   Отправить e-mail  

Проблема с алгоритмом чтения данных из файла

neitro
Все работает достаточно долго
Сколько длится построчное чтение без действий?



Офлайн

#5 Июль 15, 2015 00:38:26

neitro
Зарегистрирован: 2015-03-13
Сообщения: 25
Репутация: +  0  -
Профиль   Отправить e-mail  

Проблема с алгоритмом чтения данных из файла

py.user.next
Сколько длится построчное чтение без действий?
Около минуты без операций проверки
что то в таком духе
f=open('file.csv','r')
for line in f:
if id in line: k+=1

Budulianin
На память тут нагрузки вообще не будет, благодаря итератору.
Если я считываю построчно - то в буфер ничего не идет, но если я файл превращу в массив, то он скушает достаточно неплохо (насколько я понимаю).
С другой стороны: не перегоняя в массив я не могу обращаться поэлементно - поэтому метод половинного деления и т.д. использовать не получится.

Budulianin
Предварительно разбить файл на части и обработать их параллельно, 1 процесс на ядро процессора.
Т.е. процессор должен быть с несколькими ядрами.
Да была мысль разбить его по частям по принципу 1-х нескольких символов, но как то это не правильно.
Загружать в бд - тоже не имеет смысла, т.к. доступ к этой информации нужен не так часто.

JOHN_16
читать кусок файла ( буфер ) в память и его обрабатывать там. Но это только в том случае если действительно это проблемное место. Иначе выигрыша не дает.

Вот я и не могу понять, что я могу прочитать кроме 1 строки) Могу ли я считать разом 1000 строк ( не символов), а не построчно. Я знаю, что есть функция readlines, но при больших размерах ее юзать не рекомендуют, а делать код, который будет в будущем глючить считаю не совсем правильно.

PS Забыл сказать, что строки отсортированы по id, что должно упрощать жизнь… по задумке)

Офлайн

#6 Июль 15, 2015 08:04:56

Budulianin
От:
Зарегистрирован: 2011-10-18
Сообщения: 1218
Репутация: +  33  -
Профиль   Отправить e-mail  

Проблема с алгоритмом чтения данных из файла

Последний раз говорю, код в теги оберни.

neitro
Если я считываю построчно - то в буфер ничего не идет, но если я файл превращу в массив, то он скушает достаточно неплохо (насколько я понимаю).
С другой стороны: не перегоняя в массив я не могу обращаться поэлементно - поэтому метод половинного деления и т.д. использовать не получится.

Какое ещё половинное деление? Я ничего про это не говорил.

neitro
Да была мысль разбить его по частям по принципу 1-х нескольких символов, но как то это не правильно.
Не знаю, что у тебя за принцип, может быть он не правильный.
То что предложил я - вполне логично и просто.



Офлайн

#7 Июль 15, 2015 09:39:55

py.user.next
От:
Зарегистрирован: 2010-04-29
Сообщения: 10016
Репутация: +  857  -
Профиль   Отправить e-mail  

Проблема с алгоритмом чтения данных из файла

neitro
Около минуты без операций проверки
Вообще-то, csv нужно читать специальным модулем, потому что разделитель может появляться внутри поля в виде обычного символа.
Построчное чтение тоже может обернуться тем, что перевод строки будет внутри поля в виде части текста.
В то же время модуль csv знает про экранирование, поэтому правильно раскладывает на поля.

Если размер растёт, лучше использовать какой-нибудь sql-формат базы данных.



Отредактировано py.user.next (Июль 15, 2015 09:40:31)

Офлайн

#8 Июль 15, 2015 22:50:25

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

Проблема с алгоритмом чтения данных из файла

py.user.next
Если размер растёт
Поддержу. Задача совершенно не поставлена. Файл меняется или нет? Насколько часто запросы к нему будут возникать? Какие требования к времени выполнения запроса? Строки в файле одинаковой длины? А так конечно напрашивается перегнать его в sqlite и не морочиться.



Офлайн

#9 Июль 15, 2015 23:39:53

neitro
Зарегистрирован: 2015-03-13
Сообщения: 25
Репутация: +  0  -
Профиль   Отправить e-mail  

Проблема с алгоритмом чтения данных из файла

Budulianin
Последний раз говорю, код в теги оберни.
Код приведен для понимания, что я сделал - вопрос теоретический по большей части.
Budulianin
Не знаю, что у тебя за принцип, может быть он не правильный.
То что предложил я - вполне логично и просто.
Насколько я понимаю “тормоза” идут из за большого кол-ва операций сравнивания. У меня этих оперцаций для каждого id 1 000 000, если бы воспользоваться методом половинного деления кол-во операций уменьшиться до 20 операций за круг
Budulianin
Не знаю, что у тебя за принцип, может быть он не правильный.
То что предложил я - вполне логично и просто.
Неправильно предположим, что разбиваем по 1-м 5-ти символам, т.е. получаем файлы вида ‘a1b2с.txt’, но где находятся id 2-3-4 символьные. Это сильно усложнит логику задачи. А при дальнейшем увеличении данных - еще на n частей

doza_and
Поддержу. Задача совершенно не поставлена. Файл меняется или нет? Насколько часто запросы к нему будут возникать? Какие требования к времени выполнения запроса? Строки в файле одинаковой длины? А так конечно напрашивается перегнать его в sqlite и не морочиться.
Регулярность - произвольная (не более 20раз/месяц). Требования по времени - минимальное (как всегда).
Ограничение на длину строки нет - там информация лежит достаточно произвольная.

Использовать SQL - едва ли целесообразно (ради нескольких раз в месяц - грузить систему инфой) + интересно найти некое решение для больших данных.

Офлайн

#10 Июль 16, 2015 08:06:57

ayb
Зарегистрирован: 2014-04-01
Сообщения: 297
Репутация: +  24  -
Профиль   Отправить e-mail  

Проблема с алгоритмом чтения данных из файла

neitro
У меня этих оперцаций для каждого id 1 000 000, если бы воспользоваться методом половинного деления кол-во операций уменьшиться до 20 операций за круг

Т.е. если у Вас программа нашла строку с нужным id она все равно продолжит искать дальше ? И каким образом кол-во операций уменьшиться до 20 за круг ?

Вы бы показали код, вполне возможно что там что-то не так. Вот я попробовал смоделировать вашу ситуацию, незнаю насколько точно получилось :

from random import choice
from string import ascii_letters as l
from string import digits as d
import linecache
import time
# generate data for test
def gen_data():
    with open('data', 'w') as file:
        for i in range(999999):
            file.write('%s ; %s \n' % (''.join([choice(d+l) for _ in range(10)]),
                                       ''.join([choice(d+l) for _ in range(300)])))
        file.close()
# generate ids list to search for
def gen_ids():
    with open('ids', 'w') as file:
        for i in range(4999):
            line = linecache.getline('data', choice(range(999999)))
            file.write('%s\n' % line.split(' ;')[0])
        file.close()
start = time.time()
counter = 0
ids = [x.strip() for x in open('ids', 'r')]
with open('data', 'r') as file:
    for line in file:
        if line.split(' ;')[0] in ids:
            counter += 1
            ids.remove(line.split(' ;')[0])
print(counter)
print(time.time() - start)
4989
192.94302320480347

Это на ( уже ) стареньком Phenom II X4 9600. Скрипт скушал 2.8 Мб оперативки, и честно загрузил на полную одно ядро. На более современном процессоре должно быть быстрее.

EDIT : немного подправил, после того как id совпало его можно удалять из списка проверки. Получилось 72 секунды.

Отредактировано ayb (Июль 17, 2015 10:18:27)

Офлайн

Board footer

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

Powered by DjangoBB

Lo-Fi Version