2016-07-01 13 views
2

У меня есть скрипт, который обрабатывает пакет из 20MiB CSV-файлов, опционально gzip-сжатый до примерно 4MiB. Существует много тысяч файлов, и каждая обработка по отдельности занимает около 30 секунд; читая либо несжатый файл, либо сжатый файл, а декомпрессию «почти мгновенно», что очень важно, чтобы процесс можно было распараллелить на уровне процесса. Действительно, это то, что делается с использованием сложного Ruby-конвейера. Тем не менее, я пытаюсь разбить код Ruby на более мелкие части, используя bash. Для контроля работы, я бы придумал эту функцию БашПодстановка замещения процесса Bash с управлением заданиями

wait_until_job_available() { 
    maximum_jobs=${MAXIMUM_JOBS} 
    [ $# -eq 0 ] || maximum_jobs="${1}" 
    exit_status=0 
    RUNNING_JOBS=($(jobs -p)) 
    while [ ${maximum_jobs} -le ${#RUNNING_JOBS[@]} ] && [ 0 -eq "${exit_status}" ] 
    do 
     # `wait -n` requires bash 4.3 which is unfortunately not available on several recent RHEL-based Linux distributions such as Oracle Linux 
     wait -n 
     exit_status=$? 
     RUNNING_JOBS=($(jobs -p)) 
    done 
    return ${exit_status} 
} 

Это позволяет мне позвонить wait_until_job_available, с дополнительным минимальным количеством выполнения заданий разрешено (если опущен, то по умолчанию количество ядер доступны на машина), перед тем, как основываться на трубопроводе bash.

Так что я мог бы использовать его, как, например:

while read file 
do 
    CAT_COMMAND=cat 

    # if input file is gzip-compressed, pipe zcat instead of cat 
    if [ "${INFILE: -3}" == ".gz" ] 
    then 
     CAT_COMMAND=zcat 
    fi 

    # wait for a job to become available 
    wait_until_job_available 

    # read the uncompressed file, write processed data to file.out 
    process_file -i <(${CAT_COMMAND} ${file}) -o ${file}.out & 

# while searching for filesystem paths of type _f_ile 
done < <(find ${search_path} -type f) 

# wait for all background jobs to finish 
wait 

Как вы можете видеть, это должно найти все файлы в search_path и передать команде process_file. При этом я использую подстановку процессов либо в файл cat, либо при распаковке файла на лету; имя входного файла заменяется процессом, который будет выдавать содержимое несжатого файла, а выходной файл - это исходное имя файла с добавлением «.out». Invokeation process_file получает справочную информацию и отправляется на управление заданиями. Выглядит денди, да?

За исключением того, что я заметил, что некоторые файлы не совсем корректно обрабатываются.

Я заметил, что файл, который, как считается, обрабатывается process_file, всегда сообщается как /dev/fd/63, даже для отдельных одновременных экземпляров process_file. С другой стороны, когда я отдельно копирую или распаковываю файл на временный и передаю имя временного файла на process_file, выполнение выполняется нормально, и все файлы выглядят корректно обработанными.

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

Для справки, я использую Ubuntu Server 14.04, Linux 3.19.0-59 Bash 4.3.11 GZIP 1,6

ответ

1

Я сделал немного копать и может быть в состоянии указать вам в праве направление.

По-видимому,/dev/fd/63 является стандартным файловым дескриптором, используемым process_file. Поэтому, когда вы запускаете несколько экземпляров process_file, он пытается отправить все через этот файловый дескриптор. Вы, вероятно, создаете конфликт или состояние гонки, как вы подозреваете.

На этой странице file descriptors and bash shell scripting и на этой странице redirection_tutorial есть примеры для перенаправления выходов.

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

+0

С моей точки зрения, файловый дескриптор создается Bash, хотя – inetknght