Является ли python автоматическим распараллеливанием разделов IO- и CPU- или памяти?

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

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

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() происходит параллельно с IO.

Это хорошая новость!

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

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

Ответ 1

Очевидно, data.append() происходит параллельно с IO.

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

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

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

Для интерфейса Python для fadvise см. python-fadvise.

Ответ 2

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

Ответ 3

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

Ответ 4

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

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

Ответ 5

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