Python: как ускорить загрузку этого файла

Я ищу способ ускорить загрузку файла следующим образом:

Данные содержат около 1 миллиона строк, табуляция разделена символом "\t" (символ табуляции) и кодировка utf8, для анализа полного файла с приведенным ниже кодом требуется около 9 секунд. Тем не менее, я хотел бы быть почти в порядке секунды!

def load(filename):
    features = []
    with codecs.open(filename, 'rb',  'utf-8') as f:
        previous = ""
        for n, s in enumerate(f):
            splitted = tuple(s.rstrip().split("\t"))
            if len(splitted) != 2:
                sys.exit("wrong format!")
            if previous >= splitted:
                sys.exit("unordered feature")
            previous = splitted
            features.append(splitted)
    return features   

Мне интересно, могут ли какие-либо данные двоичного формата что-то ускорить? Или, если бы я мог воспользоваться некоторыми NumPy или любыми другими библиотеками, чтобы иметь более высокую скорость загрузки.

Может быть, вы могли бы дать мне совет по поводу другого узкого места в скорости?

РЕДАКТИРОВАТЬ: попробую некоторые из ваших идей, спасибо! Кстати, мне действительно нужен кортеж (строка, строка) внутри огромного списка... вот результаты, я получаю 50% времени :) теперь я собираюсь позаботиться о двоичных данных NumPy, как я заметил что еще один огромный файл действительно очень быстро загружался...

import codecs

def load0(filename): 
    with codecs.open(filename, 'rb',  'utf-8') as f: 
    return f.readlines() 

def load1(filename): 
    with codecs.open(filename, 'rb',  'utf-8') as f: 
    return [tuple(x.rstrip().split("\t")) for x in f.readlines()]

def load3(filename):
    features = []
    with codecs.open(filename, 'rb',  'utf-8') as f:
    for n, s in enumerate(f):
        splitted = tuple(s.rstrip().split("\t"))
        features.append(splitted)
    return features

def load4(filename): 
    with codecs.open(filename, 'rb',  'utf-8') as f: 
    for s in f: 
        yield tuple(s.rstrip().split("\t")) 

a = datetime.datetime.now()
r0 = load0(myfile)
b = datetime.datetime.now()
print "f.readlines(): %s" % (b-a)

a = datetime.datetime.now()
r1 = load1(myfile)
b = datetime.datetime.now()
print """[tuple(x.rstrip().split("\\t")) for x in f.readlines()]: %s""" % (b-a)

a = datetime.datetime.now()
r3 = load3(myfile)
b = datetime.datetime.now()
print """load3: %s""" % (b-a)
if r1 == r3: print "OK: speeded and similars!"

a = datetime.datetime.now()
r4 = [x for x in load4(myfile)] 
b = datetime.datetime.now()
print """load4: %s""" % (b-a)
if r4 == r3: print "OK: speeded and similars!"

Результаты :

f.readlines(): 0:00:00.208000
[tuple(x.rstrip().split("\t")) for x in f.readlines()]: 0:00:02.310000
load3: 0:00:07.883000
OK: speeded and similars!
load4: 0:00:07.943000
OK: speeded and similars!

что-то очень странное в том, что я замечаю, что у меня может быть почти удвоенное время в двух последовательных запусках (но не каждый раз):

>>> ================================ RESTART ================================
>>> 
f.readlines(): 0:00:00.220000
[tuple(x.rstrip().split("\t")) for x in f.readlines()]: 0:00:02.479000
load3: 0:00:08.288000
OK: speeded and similars!
>>> ================================ RESTART ================================
>>> 
f.readlines(): 0:00:00.279000
[tuple(x.rstrip().split("\t")) for x in f.readlines()]: 0:00:04.983000
load3: 0:00:10.404000
OK: speeded and similars!

ПОСЛЕДНЯЯ РЕДАКТИРОВАТЬ: ну, я попытался изменить, чтобы использовать numpy.load... это очень странно для меня... из "обычного" файла с моими 1022860 строками и 10 КБ. После выполнения numpy.save(numpy.array(load1(myfile))) я получил 895 МБ! а затем перезагружая это с помощью numpy.load(), я получаю такое время при последовательных запусках:

  >>> ================================ RESTART ================================
  loading: 0:00:11.422000 done.
  >>> ================================ RESTART ================================
  loading: 0:00:00.759000 done.

может быть, numpy делает некоторые вещи с памятью, чтобы избежать перезагрузки в будущем?


person user1340802    schedule 03.09.2012    source источник
comment
Что ты пытаешься сделать? Почему вы сравниваете строки previous и splitted именно так? Вы изучали понимание списка? Например, см. этот связанный пост SO .   -  person Tim    schedule 03.09.2012
comment
на самом деле это сравнение - просто способ убедиться, что формат файла в порядке. Удалив эти 2 теста, я получаю только 09,09 => 08,38 секунды. Моя настоящая проблема заключается в том, как я могу как можно быстрее прочитать вкладку кортежа (строка, строка) смешивания файлов, разделенную как можно быстрее. Я почти могу удалить эти тесты, кстати, делаю это, я все еще медленнее на 7 секунд :/   -  person user1340802    schedule 03.09.2012
comment
Вам действительно нужно собрать все функции в большой список? Может быть, вы можете просто пройтись по линиям, сделав это функцией генератора, и перебрать ее.   -  person Keith    schedule 03.09.2012
comment
@Keith, ну, я не знаю, на самом деле я пытаюсь ускорить внешнюю библиотеку (лицензия MIT), которую я хотел встроить в веб-сервис, я заметил, что огромным узким местом была загрузка этих функций. Я должен погрузиться глубже, чтобы проверить, смогу ли я реорганизовать все это... но это может быть не моим главным приоритетом - ускорить его, не переписывая все, будет достаточно на данный момент.   -  person user1340802    schedule 04.09.2012


Ответы (3)


проверьте, сколько секунд на самом деле нужно прочитать строки файла, например

def load(filename):
    features = []
    with codecs.open(filename, 'rb',  'utf-8') as f:
        return f.readlines()

Если оно значительно меньше 9 с, то

  1. попробуйте использовать многопроцессорность и разделить работу по проверке строк между ядрами процессора и/или
  2. используйте более быстрый интерпретатор, такой как pypy

и посмотрите, ускорит ли что-нибудь из этого

person bpgergo    schedule 03.09.2012
comment
выглядит самым быстрым, когда я загружаю его f.readlines(): 0:00:00.208000 Кстати, мне также нужно разделение, смешивание с Бурханом Халидом позволит мне выиграть много времени... посмотрю, смогу ли я войти менее 2 или 1 секунды ... Numpy может быть многообещающим, если есть какая-либо совместимая структура. - person user1340802; 04.09.2012

Попробуйте эту версию, поскольку вы упомянули, что проверка не важна, я ее устранил.

def load(filename):
    with codecs.open(filename, 'rb',  'utf-8') as f:
        for s in f:
            yield tuple(s.rstrip().split("\t"))

results = [x for x in load('somebigfile.txt')]
person Burhan Khalid    schedule 03.09.2012
comment
это очень странно, этот метод выглядит не особенно быстрым:/ посмотрите мой load4, который является вашим предложением, кстати, вдохновленный вашим ответом, load1 намного быстрее! я не могу это объяснить... сейчас я собираюсь проверить любой бинарный способ Numpy.. - person user1340802; 04.09.2012

Проверив, сколько времени требуется, чтобы просто перебрать файл, как предлагает bpgergo, вы можете проверить следующее:

  • Если вы знаете, что ваш файл содержит 10 ^ 6 строк, вы можете предварительно выделить список. Это должно быть быстрее, чем добавление к нему на каждой итерации. Просто используйте features = [None] * (10 ** 6) для инициализации списка
  • Не приводить результат split() к кортежу, в этом нет необходимости.
  • Вы, кажется, совсем не получаете выгоды от enumerate. Просто используйте: for line in f: вместо for n, s in enumerate(f):
person Abgan    schedule 03.09.2012
comment
я думаю, что приведение к кортежу было необходимо для проверки порядка с previous >= splitted, но я могу ошибаться... - person user1340802; 04.09.2012
comment
@ user1340802: split() возвращает список, поэтому его можно сравнивать точно так же, как кортеж. Единственная польза от приведения может заключаться в том, что автору нужны неизменяемые записи при последующей обработке. - person Abgan; 05.09.2012
comment
@Dougal: я не говорил, что он должен попробовать все мои советы одновременно :) - person Abgan; 05.09.2012