2009-05-11 1 views
11

Рассмотрим питона программу:Возможно ли ускорение ввода-вывода python?

import sys 

lc = 0 
for line in open(sys.argv[1]): 
    lc = lc + 1 

print lc, sys.argv[1] 

Запуск на моем текстовом файле 6GB, он завершает в ~ 2мин.

Вопрос: можно ли ехать быстрее?

Обратите внимание, что в то же время требуется:

wc -l myfile.txt 

так, я подозреваю, что Anwer моему quesion это обычный «нет».

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

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

Смотрите также follow-up question

+3

взглянуть на очень похожем обсуждение здесь: http://stackoverflow.com/questions/845058/how-to-get-line-count-cheaply-in-python – SilentGhost

+3

Вероятно, большая часть времени здесь проводится ожидание на диске. –

+0

Я опаздываю на вечеринку, но для больших файлов "sed -n '$ =' filename" быстрее, чем "wc -l" – philshem

ответ

3

Вы не можете получить скорость выше максимальной скорости чтения.

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

  1. прочитать файл в с большим буфером. Это может быть закодировано «вручную» или просто с помощью io.BufferedReader (доступно в python2.6 +).
  2. Выполняйте подсчет новой строки в другом потоке параллельно.
+2

-1 не вижу, как ускорение новой строки в другом потоке может ускориться. Это просто замедлит работу. Ожидание потоков не заставит вас ждать быстрее. – nosklo

+4

Обычно вы были бы правы. Однако в этом случае чтение потока из файла будет ожидать ввода-вывода, в то время как другой поток анализирует новые строки. Таким образом - поток читателя не будет ждать, пока поток парсера будет разбирать символы новой строки между последующими чтениями. – Barakando

+0

Я принимаю этот ответ, хотя в этом конкретном случае это не стоит усилий, поскольку работа за строчку очень низкая, и я уже нахожусь на максимальной скорости. Дополнительную информацию см. Также в следующем вопросе. – Davide

5

равнине "нет".

Вы в значительной степени достигли максимальной скорости диска.

Я имею в виду, вы могли бы mmap файл, или прочитать его в двоичных кусках, и использовать .count('\n') или что-то в этом роде. Но это вряд ли даст значительные улучшения.

4

Если вы считаете, что диск может читать 60 МБ/с, вам понадобится 6000/60 = 100 секунд, что составляет 1 минуту 40 секунд. Я не думаю, что вы можете получить быстрее, потому что диск является узким местом.

+1

Откуда это 20 в ваших расчетах? Возможно, вы имели в виду 6000/60 = 100? 60 не 20, верно? –

+0

Я сначала хотел вычислить его с 20 Мбайт/с, но потом я подумал, что это слишком медленно. –

1

как уже говорили другие - «нет»

Почти все свое время не тратится на ожидание ввода-вывода. Если это то, что вам нужно делать не один раз, и, у вас есть машина с тоннами барана, вы можете сохранить файл в памяти. Если ваша машина имеет 16 ГБ оперативной памяти, у вас будет 8 ГБ в/dev/shm для игры.

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

1

Обратите внимание, что Python I/O реализован на C, поэтому нет большой удачи, ускоряя его дальше.

+2

Вы можете написать совершенно плохой и медленный код C, поэтому, если он написан на C, он не гарантирует, что он будет быстрым. И могут быть накладные расходы (например, для интерпретации байт-кода, для чтения по строкам и итерации и т. Д.), Что может замедлить его. – Davide

12

Бросьте аппаратуру в проблему.

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

Редактировать: Еще один хороший момент по gs; вы также можете использовать конфигурацию RAID, чтобы улучшить скорость. Это можно сделать либо с помощью, либо программного обеспечения (например, OS X, Linux, Windows Server и т. Д.).


управляющих Уравнение

(Amount to transfer)/(transfer rate) = (time to transfer)

(6000 MB)/(60 MB/s) = 100 seconds

(6000 MB)/(125 MB/s) = 48 seconds


Аппаратные решения

The ioDrive Duo, возможно, является самым быстрым решением для корпоративных условий и «будет доступен в апреле 2009 года».

Или вы можете проверить жесткий диск WD Velociraptor (10 000 об/мин).

Кроме того, я слышал, что Seagate Cheetah является хорошим вариантом (15 000 об/мин с устойчивой скоростью передачи 125 МБ/с).

+3

RAID могут быть намного быстрее. –

7

Трюк заключается не в том, чтобы заставить электроны двигаться быстрее (это трудно сделать), а для того, чтобы сделать больше работы за единицу времени.

Во-первых, убедитесь, что ваш 6-гигабайтный файл считывается с привязки ввода-вывода, а не с привязки к ЦП.

Если он связан с I/O, рассмотрим шаблон проектирования «Fan-Out».

  • Родительский процесс порождает кучу детей.

  • Родитель читает файл 6 Гб и передает строки дочерним элементам, записывая их в свои трубы STDIN. Время чтения 6 ГБ останется постоянным. Задание строки должно включать как можно меньшую родительскую обработку. Должны использоваться очень простые фильтры или подсчеты.

    Труба - это канал в памяти для связи. Это общий буфер с читателем и писателем.

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

+0

возможно (на третьей пуле) вы имели в виду, что все дети должны разговаривать друг с другом в памяти, так как диск уже очень занят. – Davide

+0

Трубы * - * каналы связи в памяти. –

+0

Да, но в вашей третьей марке вы написали: «Каждый ребенок должен, вероятно, написать простой файл на диске». – Davide

1

2 минуты звучат о праве читать весь файл 6gb. На самом деле, вы не можете сделать так, чтобы алгоритм или ОС ускорили работу.Я думаю, у вас есть два варианта:

  1. Бросьте деньги на проблему и получите лучшее оборудование. Вероятно, лучший вариант, если этот проект для вашей работы.

  2. Не читайте весь файл. Я не знаю, что вы пытаетесь сделать с данными, поэтому, возможно, у вас нет выбора, кроме как прочитать все. С другой стороны, если вы сканируете весь файл на одну конкретную вещь, то, возможно, поставить некоторые метаданные там с самого начала было бы полезно.