GNU parallel: назначьте один поток для каждого узла (каталогов и подкаталогов *) всего дерева из начального каталога

#multithreadin& #parallel-processin& #tree #find #&nu-parallel

#многопоточность #параллельная обработка #дерево #Найти #&nu-parallel

Вопрос:

Я хотел бы воспользоваться всем потенциалом parallel command в macOS (кажется, существует 2 версии, версия GNU и Ole Tan&e, но я не уверен).

С помощью следующей команды:

 parallel -j8  find {} ::: *
  

У меня будет большая производительность, если я буду находиться в каталоге, содержащем 8 подкаталогов.
Но если все эти подкаталоги имеют небольшое содержимое, за исключением только одного, у меня будет только один поток, который будет работать с уникальным «большим» каталогом.

  1. Есть ли способ выполнить распараллеливание для этого «большого каталога»? Я имею в виду, могут ли другие потоки (предыдущий, который работал с небольшими подкаталогами) помочь оставшемуся уникальному потоку?

    Идеальным случаем была бы параллельная команда «переключаться автоматически», когда find командой в командной строке выше найдены все небольшие подразделы. Может быть, я прошу слишком многого?

  2. Другая потенциальная оптимизация, если она существует: учитывая общую древовидную структуру каталогов: есть ли способ, подобный, например, команде make -j8 , назначить каждый текущий поток вложенному каталогу (sub-(sub- ….)))) и как только текущий каталог будет исследован (не забывайте, я хотел бы в основном использовать эту оптимизацию с find командой Linux), другой поток исследует другой каталог вложенный (sub-(sub- …. )))) каталог?

    Конечно, общее количество запущенных потоков не больше числа, указанного с помощью parallel command ( parallel -j8 в моем примере выше): мы можем сказать, что если количество элементов дерева (1 узел = 1 каталог) больше, чем количество потоков, мы не можем превысить это число.

    Я знаю, что распараллеливание в рекурсивном контексте сложно, но, может быть, я смогу получить существенный фактор, когда захочу найти файл в большой древовидной структуре?

    Вот почему я беру пример command make -j8 : я не знаю, как это закодировано, но это заставляет меня думать, что мы могли бы сделать то же самое с командной строкой couple parallel/find в начале моего поста.

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

ОБНОВЛЕНИЕ 1: Как сказал @OleTan&e, я априори не знаю структуру каталогов того, что я хочу &updatedb проиндексировать. Таким образом, maxdepth трудно знать заранее. Ваше решение интересно, но первое выполнение find не является многопоточным, вы не используете parallel команду. Я немного удивлен, что многопоточной версии &updatedb не существует : на бумаге это возможно, но как только мы захотим закодировать его в скрипте GNU &updatedb macOS 10.15, это становится сложнее.

Если у кого-то могут быть другие предложения, я бы воспользовался ими !

Ответ №1:

Если вы собираетесь выполнять распараллеливание find , вам нужно быть уверенным, что ваш диск может доставлять данные.

Для магнитных дисков вы редко увидите ускорение. Иногда для RAID, сетевых дисков и SSD и часто для NVMe.

Самый простой способ распараллеливания find — использовать */* :

 parallel find ::: */*
  

Или */*/* :

 parallel find ::: */*/*
  

Это приведет к поиску во вложенных каталогах и в каталогах sub-sub-sub.

Они не будут выполнять поиск в верхних каталогах, но это можно сделать, запустив один дополнительный, find с соответствующим -maxdepth .

Приведенное выше решение предполагает, что вы что-то знаете о структуре каталогов, поэтому это не общее решение.

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

Если бы я должен был это реализовать, это было бы что-то вроде этого (слегка протестировано):

 #!/bin/bash

tmp=$(tempfile)
myfind() {
  find "$1" -mindepth 1 -maxdepth 1
}
export -f myfind
myfind . | tee $tmp
while [ -s $tmp ] ; do
    tmp2=$(tempfile)
    cat $tmp | parallel --lb myfind | tee $tmp2
    mv $tmp2 $tmp
done
rm $tmp
  

(PS: У меня есть основания полагать, что параллель, написанная Ole Tan&e, и GNU Parallel — это одно и то же).

Комментарии:

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

2. @OleaTan&e. Спасибо за ваш быстрый ответ. Как вы сказали, я не знаю структуру каталогов априори того, что я хочу &updatedb проиндексировать. Таким образом, maxddepth трудно знать заранее. Ваше решение интересно, но первое выполнение find не является многопоточным, вы не используете parallel команду. Я немного удивлен, что многопоточной версии &updatedb не существует : на бумаге она верна, но как только мы захотим закодировать ее в скрипте GNU &updatedb для macOS 10.15, это для меня сложнее, как вы можете видеть.

3. @youpilat13 Первый вызов find находит только в текущем каталоге. Если все ваши файлы не сохранены в текущем каталоге, это не займет большую часть времени выполнения.

4. @OleTan&e . хорошо, итак, как можно адаптировать ваш скрипт, чтобы иметь возможность включать его в &updatedb команду macOS. С самого начала я просто хочу проиндексировать все файлы из основного корневого каталога, / за исключением определенных каталогов, которые ara не представляют интереса и которые я могу исключить с помощью опции —prune-paths &updatedb . Наконец, моя команда для индексации всего требуемого содержимого такова: sudo time &updatedb --prunepaths='/private/tmp /private/var/folders /private/var/tmp */Backups.backupdb /System /Volumes' --localpaths='/' --output=$HOME/locatedb_&updatedb_PARALLEL .

5. @OleTan&e В последовательной версии вся индексация занимает примерно 30 минут. Я надеюсь получить коэффициент 2 или 3 с параллельной версией, но, возможно, я слишком оптимистичен. Вы лучше понимаете проблему? С уважением. PS: кстати, благодаря тому, что я закодировал команду GNU parallel , я только что узнал, что вы являетесь автором.