распараллелить скрипт awk - расщепление файлов - PullRequest
0 голосов
/ 03 января 2019

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

cat mydir/*.csv | awk -F, '{if(NF==29)print $0 >> "output/"$2".csv"}'

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

Ответы [ 2 ]

0 голосов
/ 04 января 2019

вы можете попробовать это.

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

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

rm output/*.csv
for File in mydir/*.csv
 do
   # shell sub process
   {
   # ref for a series of temporary file
   FileRef="${File##*/}"

   awk -F ',' -v FR="${FileRef}" '
      NF == 29 {
         # put info in temporary file
         ListFiles [ OutTemp = "output/"$2".csv_" FR ] = "output/"$2".csv"
         print > OutTemp}
      END {
        # put temporary content into final file
        for ( TempFile in ListFiles ) {
           Command = sprintf( "cat \042%s\042 >> \042%s\042; rm \042%s\042" \
              , TempFile, ListFiles[TempFile], TempFile )
           printf "" | Command
           }
      ' File
    } &
 done

wait
echo ls -l output/*.csv
0 голосов
/ 04 января 2019

Непроверенные:

do_one() {
  # Make a workdir only used by this process to ensure no files are added to in parallel
  mkdir -p  $1
  cd $1
  cat ../"$2" | awk -F, '{if(NF==29)print $0 >> $2".csv"}'
}
export -f do_one
parallel do_one workdir-{%} {} ::: mydir/*.csv 
ls workdir-*/ | sort -u |
   parallel 'cat workdir*/{} > output/{}'
rm -rf workdir-*

Если вы хотите избежать дополнительных cat, вы можете использовать это вместо этого, хотя я считаю, что версию cat легче читать (производительность обычно одинакова на современных системах http://oletange.blogspot.com/2013/10/useless-use-of-cat.html):

do_one() {
  # Make a workdir only used by this process to ensure no files are added to in parallel
  mkdir -p  $1
  cd $1
  awk -F, <../"$2" '{if(NF==29)print $0 >> $2".csv"}'
}
export -f do_one
parallel do_one workdir-{%} {} ::: mydir/*.csv 
ls workdir-*/ | sort -u |
   parallel 'cat workdir*/{} > output/{}'
rm -rf workdir-*

Но, как пишет @Thor, вы, скорее всего, испытываете недостаток ввода / вывода.

...