Выполняет ли python автоматическое распараллеливание разделов ввода-вывода, процессора или памяти?

Это дополнительные вопросы к предыдущему.

Рассмотрим этот код, который менее забавен, чем код в предыдущем вопросе (но все же намного проще моего настоящего)

import sys
data=[]

for line in open(sys.argv[1]):
    data.append(line[-1])

print data[-1]

Теперь я ожидал более продолжительного времени работы (мой тестовый файл состоит из 65150224 строк), возможно, намного дольше. Это не тот случай, он работает примерно за 2 минуты на том же HW, что и раньше!

Является ли data.append () очень легким? Я в это не верю, поэтому я написал этот фальшивый код, чтобы проверить его:

data=[]
counter=0
string="a\n"

for counter in xrange(65150224):
    data.append(string[-1])

print data[-1]

Это занимает от 1,5 до 3 минут (между запусками сильно различается).

Почему я не получаю от 3,5 до 5 минут в прежней программе? Очевидно, что data.append () выполняется параллельно с вводом-выводом.

Это хорошие новости!

Но как это работает? Это задокументированная функция? Есть ли какие-либо требования к моему коду, которым я должен следовать, чтобы он работал в максимально возможной степени (помимо балансировки нагрузки ввода-вывода и операций с памятью / процессором)? Или это просто буферизация / кеширование в действии?

Опять же, я пометил этот вопрос "linux", потому что меня интересуют только ответы, специфичные для linux. Не стесняйтесь давать ответы, не зависящие от ОС или даже от других ОС, если вы считаете, что это стоит того.


person Davide    schedule 13.05.2009    source источник
comment
Это другое, но все же стоит прочитать: stackoverflow.com/questions/172720/speeding-up-python   -  person Davide    schedule 14.05.2009


Ответы (5)


Очевидно, что data.append () выполняется параллельно с вводом-выводом.

Я не боюсь. В Python можно распараллелить ввод-вывод и вычисления, но это не происходит волшебным образом.

Вы можете использовать posix_fadvise(2), чтобы указать ОС, что вы планируете читать файл последовательно (POSIX_FADV_SEQUENTIAL).

В некоторых грубых тестах при выполнении команды "wc -l" на 600-мегабайтном файле (ISO) производительность увеличилась примерно на 20%. Каждый тест проводился сразу после очистки кеша диска.

Чтобы узнать об интерфейсе Python, см. python-fadvise.

person Benji York    schedule 13.05.2009

Насколько велики строки в вашем файле? Если они не очень длинные (вероятно, подойдет все, что меньше 1 КБ), вы, вероятно, заметите прирост производительности из-за буферизации ввода.

person David Locke    schedule 13.05.2009

Как вы думаете, почему list.append () будет работать медленнее? Это очень быстро, учитывая, что массивы внутренних указателей, используемые списками для хранения ссылок на объекты в них, распределяются во все более крупных блоках, так что каждое добавление фактически не перераспределяет массив, и большинство из них может просто увеличить счетчик длины и установить указатель и увеличить.

person Community    schedule 13.05.2009
comment
Ну, это выделение памяти, и это обычно не легкий процесс. Я не знаю деталей виртуальной машины python, но она либо выделяет 65150224 небольших объектов (может быть, быстро, но повторяется слишком много раз), либо, что более вероятно, удваивает размер выделения ~ 26 раз в течение всей программы (2 ^ 26 ~ 64M) во все более крупных фрагментах памяти, которые, возможно, труднее найти из-за фрагментации памяти (или дефрагментации?) - person Davide; 19.05.2009

Я не вижу никаких доказательств того, что «data.append () происходит параллельно с вводом-выводом». Как и Бенджи, я не думаю, что это происходит автоматически, как вы думаете. Вы показали, что выполнение data.append (строка [-1]) занимает примерно столько же времени, что и lc = lc + 1 (по сути, совсем нет времени по сравнению с вводом-выводом и разделением строк). Неудивительно, что data.append (строка [-1]) работает очень быстро. Можно было бы ожидать, что вся строка будет в быстром кеше, и, как уже отмечалось, append заранее подготавливает буферы и лишь изредка приходится перераспределять. Более того, строка [-1] всегда будет '\ n', за исключением, возможно, последней строки файла (не знаю, оптимизирует ли Python для этого).

Единственное, что меня немного удивляет, это то, что xrange очень изменчивый. Я ожидал, что он всегда будет быстрее, поскольку нет ввода-вывода, и вы фактически не используете счетчик.

person Matthew Flaschen    schedule 14.05.2009

Если время выполнения для второго примера различается на эту величину, я подозреваю, что ваш метод измерения времени или внешние воздействия (другие процессы / загрузка системы) искажают время до такой степени, что они не дают никакой надежной информации.

person Doug    schedule 14.05.2009
comment
Конечно, возможно, ты прав. Но ведь это может быть и фрагментация памяти, не так ли? - person Davide; 19.05.2009
comment
Я бы не решился обвинить фрагментацию памяти в таких резких различиях. Я не могу сказать наверняка, но я склонен полагать, что многие структуры данных в Python страдают от фрагментации из-за природы языка. В этом конкретном случае я мог бы подумать, что подкачка является более вероятной причиной, чем фрагментация. - person Doug; 21.05.2009