Найти - Пользователи
Полная версия: Проблема с алгоритмом чтения данных из файла
Начало » Python для новичков » Проблема с алгоритмом чтения данных из файла
1
neitro
Здравствуйте, ув форумчане!
Задачка следующая:
имеется файл (файл достаточно большой ~ 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 раз)
Какие есть варианты кроме построчного чтения строк?

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

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 процесс на ядро процессора.
py.user.next
neitro
Все работает достаточно долго
Сколько длится построчное чтение без действий?
neitro
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, что должно упрощать жизнь… по задумке)
Budulianin
Последний раз говорю, код в теги оберни.

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

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

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

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

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

Использовать SQL - едва ли целесообразно (ради нескольких раз в месяц - грузить систему инфой) + интересно найти некое решение для больших данных.
ayb
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 секунды.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB