как добавить несколько файлов, используя многопоточность в Bash - PullRequest
1 голос
/ 25 апреля 2019

как мы можем добавить несколько файлов в один файл, используя многопоточность, каждый мой файл имеет 10M строк. поэтому я хочу обрабатывать все файлы одновременно?

 #!/bin/bash
appendFiles  A.TXT &
appendFiles  B.TXT &
appendFiles  C.TXT &
wait

function appendFiles 
 {
while  read -r line; do
echo $line >>final.txt
done < $1
} 

Ответы [ 3 ]

5 голосов
/ 25 апреля 2019

Вы пытались использовать простой cat, например, такой:

cat A.txt B.txt C.txt > final.txt

Это намного быстрее, чем чтение каждого файла построчно, даже если это делается параллельно.

ТакжеВы также можете попробовать параллельную cat, но для моих тестов это было не быстрее, чем в одной команде.(Проверено с тремя файлами около 10 миллионов строк)

#!/bin/bash
appendFiles  A.TXT &
appendFiles  B.TXT &
appendFiles  C.TXT &
wait

function appendFiles 
{
   cat "$1" >> final.txt
} 
3 голосов
/ 25 апреля 2019

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

В качестве основного исправления терминологии здесь нет потоков.Существует две разные модели параллелизма, и Bash поддерживает только одну из них, а именно многопроцессорность. Потоки выполняются внутри одного процесса;но в Bash нет никакого способа управлять внутренними компонентами других процессов (и это в любом случае было бы довольно проблематично).Bash может запускать и останавливать процессы (не потоки) и делает это очень хорошо.

Но добавление параллелизма ЦП в попытке ускорить выполнение задач, не связанных с ЦП, является совершенно ошибочной идеей,Причина, по которой ввод-вывод занимает много времени, заключается в том, что ваш диск работает медленно.Ваш процессор простаивает большую часть времени, пока вращающийся диск (или даже твердотельный накопитель) заполняет и освобождает буферы DMA со скоростями, которые являются ледниковыми с точки зрения процессора.

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

В добавление к этому ваше повторное внедрение с ошибкой cat будет ужасно медленным,Bash - это печально известный за то, что он очень неэффективен в while read циклах.(Основной ошибкой является цитирование , но есть угловые случаи с read, которых вы тоже хотите избежать.)

Кроме того, вы открываете файл,поиск в конце файла для добавления и закрытие его снова каждый раз в цикле.Вы можете избежать этого, переместив перенаправление за пределы цикла;

while IFS= read -r line || [[ -n $line ]]; do
    printf '%s\n' "$line"
done >>final.txt

Но это все еще страдает от мучительной медлительности while read.Если вы действительно хотите объединить эти файлы, я бы просто cat их все последовательно.

cat A.TXT B.TXT C.TXT >final.txt

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

0 голосов
/ 26 апреля 2019

Обычно диски работают лучше, если они выполняют последовательное чтение.Вот почему это, как правило, лучшее решение, если у вас один диск:

cat file1 file2 file3 > file.all

Но если ваш диск представляет собой распределенную сетевую файловую систему или систему RAID, то все может работать совершенно иначе.В этом случае вы можете повысить производительность, читая файлы параллельно.

Однако наиболее очевидное решение - плохое:

(cat file1 & cat file2 & cat file3 &) > file.all

Это потому, что вы рискуете получить первую половинустрока из file1, смешанная с последней половиной строки из file2.

Если вместо этого вы используете parcat (часть GNU Parallel), то вы не увидите этого микширования, потому что оно разработанодля защиты от этого:

parcat file1 file2 file3 > file.all

или (медленнее, но по сути то же самое):

parallel --line-buffer -j0 cat ::: file1 file2 file3 > file.all
...