2010-11-01 3 views
14

Мне интересно, есть ли способ объединить текстовые файлы unix вместе быстрее чем работает cat?Каков самый быстрый способ для нескольких файлов?

Вот проблема, с которой я столкнулся. Я строкую обработку текстового файла ~ 100G в размере . Я пытаюсь улучшить время выполнения, разбивая файл на несколько сотен меньших файлов и обрабатывая их параллельно. В конце концов я получаю файлы обратно в порядке. Время чтения/записи файла занимает несколько часов. Я хотел бы найти способ улучшить следующее:

cat file1 file2 file3 ... fileN >> newBigFile 
  1. Это требует двойной дисковое пространство как file1 ... fileN занимает 100G и затем newBigFile принимает другой 100GB, а затем file1. .. fileN получает удален

  2. данные уже в file1 ... fileN, делая cat >> берет на себя прочитать и время записи, когда все, что мне действительно нужно для сотни файлов в появляются как 1 файл ...

+0

Это звучит, как вы должны использовать что-то с немного больше мышц, чем оболочки Unix. –

+0

Я понятия не имею, о чем говорю, но можно ли манипулировать файловой записью или чем-то еще? Поскольку мне нужно было не дублировать данные, а просто объединить несколько файлов обратно в 1? – Wing

ответ

4

Быстрая, но не свободное решение? Получите накопитель SSD или флэш-память на базе PCIe. Если это то, что нужно делать на регулярной основе, увеличение скорости ввода-вывода диска будет самым экономичным и быстрым ускорением, которое вы можете получить.

+0

Спасибо, но, к сожалению, я не могу изменить файловые серверы и аппаратные средства компании ... – Wing

+2

Конечно, ваши обстоятельства могут запретить это, но если оно представлено руководству как ДОПОЛНИТЕЛЬНО к существующему серверному дисководу (вместо замены), это могут быть рассмотрены. Если вы можете использовать SSD, который используется только для этой задачи, и каждый день он экономит 2 часа обработки, я думаю, что они будут уверены в экономии средств. –

4

Возможно, dd будет быстрее, потому что вам не нужно было передавать материал между кошкой и оболочкой. Что-то вроде:

mv file1 newBigFile 
dd if=file2 of=newBigFile seek=$(stat -c %s newBigFile) 
+1

Я определенно думаю, что dd, в сочетании с удалением файлов при их копировании, как предположил Роби Басак, сделает для самого рекомбинирующего решения, не выполняя команду cp/unlink с помощью mmap. Я убежден, что ничто не будет более эффективным, чем устранение расщепления полностью. – frankc

1

все, что мне действительно нужно для сотен файлов, чтобы вновь появиться в 1 файл ...

Причина это не практично, чтобы просто присоединиться к файлам, что путь в файловой системе потому что текстовые файлы обычно не заполняют блок диска точно, поэтому данные в последующих файлах должны быть перемещены вверх, чтобы заполнить пробелы, вызывая кучу чтения/записи в любом случае.

4

Возможно ли, что вы просто не разделили файл? Вместо этого обработайте файл в кусках, установив указатель на файл в каждом из ваших параллельных рабочих. Если файл нужно обрабатывать линейным образом, это делает его более сложным, но он все равно может быть выполнен. Каждому работнику необходимо понять, что вместо того, чтобы начинать со смещения, которое вы ему даете, он должен сначала искать байта по байт в следующую новую строку +1. Каждый работник должен также понимать, что он не обрабатывает заданное количество байтов, которые вы ему даете, но должен обработать первую новую строку после заданного количества байтов, которые он выделяет для обработки.

Фактическое выделение и настройка указателя файла довольно проста. Если есть n рабочих, каждый из них обрабатывает байты размера файла n/file, а указатель файла начинается с рабочего числа * n/file_size.

Есть ли какая-то причина такого плана недостаточно?

+0

Вместо того, чтобы модифицировать рабочих, оболочка может предоставить рабочим «stdin», который уже является сегментом, над которым он должен работать, например, используя 'sed' для выбора диапазона строк.Если выход необходимо скоординировать, GNU Parallel может помочь в этом. –

+0

Все это делается в perl, где исходный скрипт пытается выполнить строковые манипуляции через весь файл 100G серийно. Прямо сейчас у меня есть это разделение файла и обработка кусков через fork(), но теперь время чтения/записи является узким местом выполнения. Мне не нужно делать начальный раскол, я полагаю, как вы сказали, но мне все же приходится записывать обработанные куски, а затем снова их объединять в 1 файл, верно? – Wing

+0

Если я не разбиваю файл и каждый процесс-потомка читает исходный файл 100G, работающий в разных строках, я получаю узкое место из 200 процессов, пытающихся прочитать один и тот же файл? – Wing

6

Когда конкатенации файлов вместе, вы можете удалить небольшие файлы, так как они получают добавляются:

for file in file1 file2 file3 ... fileN; do 
    cat "$file" >> bigFile && rm "$file" 
done 

Это позволило бы избежать необходимости в два раза больше места.

Нет другого способа волшебного создания файлов, магически связанных. API-интерфейс файловой системы просто не имеет функции, которая делает это.

6

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

$ consume big-file.txt 

вместо делать

$ consume <(cat file1 file2 ... fileN) 

Это использует Unix process substitution, иногда также называемые "анонимные именованные каналы."

Вы также можете сэкономить время и пространство, разделив ваш вход и выполнив обработку в одно и то же время; GNU Parallel имеет --pipe switch, который будет выполнять именно это. Он также может собирать выходы обратно в один большой файл, потенциально используя меньше места для царапин, так как ему нужно только сохранить количество ядер штук на диске одновременно. Если вы буквально запускаете сотни процессов одновременно, Parallel значительно повысит вашу эффективность, позволяя вам настроить количество параллелизма на ваш компьютер. Я очень рекомендую.

+0

Я не тестировал это, но это звучит как самое полезное предложение. – Michael

+0

Подстановка процесса выглядит потрясающе, потому что она не помещает вещи на диск. Таким образом, вы можете «потреблять» <(cmd1 file1) <(cmd2 file2) <(cmd3 file3) ». Однако здесь это эквивалентно более традиционному «cat file1 file2 ... | потреблению». – dfrankow

1

Существует такая вещь, как слишком много параллелизма.

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

То, что вы делаете, генерирует тонны IOPS, и физика его не существует.

2

Я считаю, что это самый быстрый способ кошке все файлы, содержащиеся в той же папке:

$ ls [path to folder] | while read p; do cat $p; done 
+0

Nice =) Это работало персиковое. требуется эхо; до завершения. – Kieveli

Смежные вопросы