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