Если оперативная память не вызывает беспокойства, то читается по очереди быстрее или читает все в ОЗУ и получает к ней доступ? - Python - программирование
Подтвердить что ты не робот

Если оперативная память не вызывает беспокойства, то читается по очереди быстрее или читает все в ОЗУ и получает к ней доступ? - Python

Если оперативная память не вызывает беспокойства (у меня близко к 200 ГБ на сервере), читается по очереди быстрее или читает все в ОЗУ и получает к ней доступ? Каждая строка будет содержать строку порядка 200-500 символов юникода. Для каждого файла имеется около 2 миллионов строк.

Линия за линией

import codecs
for i in codecs.open('unicodefile','r','utf8'):
  print i

Чтение в оперативную память

import codecs
for i in codecs.open('unicodefile','r','utf8').readlines():
  print i
4b9b3361

Ответ 1

Я использовал cProfile в файле словаря ~ 1 МБ. Я читал один и тот же файл 3 раза. Первый читает весь файл только для того, чтобы даже игровое поле с точки зрения его хранения в кеше. Вот простой код:

def first_read():
    codecs.open(file, 'r', 'utf8').readlines()

def line_by_line():
    for i in codecs.open(file, 'r', 'utf8'):
        pass

def at_once():
    for i in codecs.open(file, 'r', 'utf8').readlines():
        pass

first_read()
cProfile.run('line_by_line()')
cProfile.run('at_once()')

И вот результаты:

Строка за строкой:

         366959 function calls in 1.762 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    1.762    1.762 <string>:1(<module>)
        1    0.000    0.000    0.000    0.000 codecs.py:322(__init__)
        1    0.000    0.000    0.000    0.000 codecs.py:395(__init__)
    14093    0.087    0.000    0.131    0.000 codecs.py:424(read)
    57448    0.285    0.000    0.566    0.000 codecs.py:503(readline)
    57448    0.444    0.000    1.010    0.000 codecs.py:612(next)
        1    0.000    0.000    0.000    0.000 codecs.py:651(__init__)
    57448    0.381    0.000    1.390    0.000 codecs.py:681(next)
        1    0.000    0.000    0.000    0.000 codecs.py:686(__iter__)
        1    0.000    0.000    0.000    0.000 codecs.py:841(open)
        1    0.372    0.372    1.762    1.762 test.py:9(line_by_line)
    13316    0.011    0.000    0.023    0.000 utf_8.py:15(decode)
        1    0.000    0.000    0.000    0.000 {_codecs.lookup}
    27385    0.027    0.000    0.027    0.000 {_codecs.utf_8_decode}
    98895    0.011    0.000    0.011    0.000 {len}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
    13316    0.099    0.000    0.122    0.000 {method 'endswith' of 'unicode' objects}
       27    0.000    0.000    0.000    0.000 {method 'join' of 'str' objects}
    14069    0.027    0.000    0.027    0.000 {method 'read' of 'file' objects}
    13504    0.020    0.000    0.020    0.000 {method 'splitlines' of 'unicode' objects}
        1    0.000    0.000    0.000    0.000 {open}

Все сразу:

         15 function calls in 0.023 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.023    0.023 <string>:1(<module>)
        1    0.000    0.000    0.000    0.000 codecs.py:322(__init__)
        1    0.000    0.000    0.000    0.000 codecs.py:395(__init__)
        1    0.000    0.000    0.003    0.003 codecs.py:424(read)
        1    0.000    0.000    0.014    0.014 codecs.py:576(readlines)
        1    0.000    0.000    0.000    0.000 codecs.py:651(__init__)
        1    0.000    0.000    0.014    0.014 codecs.py:677(readlines)
        1    0.000    0.000    0.000    0.000 codecs.py:841(open)
        1    0.009    0.009    0.023    0.023 test.py:13(at_once)
        1    0.000    0.000    0.000    0.000 {_codecs.lookup}
        1    0.003    0.003    0.003    0.003 {_codecs.utf_8_decode}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
        1    0.001    0.001    0.001    0.001 {method 'read' of 'file' objects}
        1    0.010    0.010    0.010    0.010 {method 'splitlines' of 'unicode' objects}
        1    0.000    0.000    0.000    0.000 {open}

Как вы можете видеть из результатов, чтение всего файла за один раз происходит намного быстрее, но вы рискуете, что слишком большой объем памяти, помещенный в файл.

Ответ 2

Ничто не мешает вам проверить это на вашей машине. Я создал файл с 1M строк каждый и результаты, приуроченные к

time python something.py > /dev/null

были:

Line-на-Line:

real    0m4.878s
user    0m4.860s
sys     0m0.008s

Чтение в ОЗУ:

real    0m0.981s
user    0m0.828s
sys     0m0.148s

Я получил MemoryError при попытке с 2M строк, по 300 символов, но вышеизложенное говорит о том, что чтение в RAM будет быстрее.

Ответ 3

Глядя на код кода, опубликованный OP, я думаю, что есть непонимание того, что делает Python.

Т.е:

"Чтение строки за строкой"

import codecs
for i in codecs.open('unicodefile','r','utf8'):
  print i

Вышеприведенное выглядит так, как будто оно читается по строкам. Однако Python интерпретирует это как "как большую часть файла в памяти, а затем обрабатывает каждый как строку". Таким образом, вышесказанное для цикла читает все в памяти.

"Чтение в ОЗУ"

import codecs
for i in codecs.open('unicodefile','r','utf8').readlines():
  print i

Я считаю, что приведенное выше практически то же, что и пример "строка за строкой" выше. Т.е., Python читает все это в памяти.

Если вы хотели протестировать линейную производительность, вам понадобится "readline()", а не "readlines()" или неуказанный цикл, что может означать "readlines()". Это отмечено в другом месте на сайте StackOverflow.

Еще один аспект, который следует учитывать, - буферизация файловой системы. Если вы используете один и тот же бит кода для одного и того же файла, тогда вы рискуете сбросом файловой системы, загрязняя результаты. Как вы говорите, у вас есть 200 ГБ оперативной памяти, этого более чем достаточно, чтобы достаточно буферизировать файл, чтобы повлиять на результаты запуска.

Для обеспечения чистых результатов тестирования вам необходимо выполнить следующие действия:

1) скопируйте большой файл из известного источника в новое имя файла. (Файловая система не должна быть файловой системой COW.) 2) очистить кеш файловой системы 3) запустите первый тест против файла. 4) удалить файл 5) скопируйте файл из источника в другое новое имя файла. 6) очистить кеш файловой системы 7) запустите второй тест против нового файла.

Это даст вам более точный тест времени загрузки файлов.

Если вы хотите загрузить весь файл в память сразу, не будет ли filehandle.read(чтение в байтах) потенциально обеспечить более быстрое средство чтения блоков в содержимом файла?

В любом случае для справки:

http://docs.python.org/2/tutorial/inputoutput.html

Ответ 4

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