LINUX.ORG.RU

Оптимизация скрипта очистки хранилища архивов

 


0

1

Дратути. Меня зовут Модест. И я программирую на HTML.

ПАМАГИТИ.

У Модеста есть скрипт. Скрипт есть у Модеста в котором обрабатывается хранилище архивов с изображениями.

Скрипт составляет список архивов в хранилище, потом ищет в каждом архиве файлы изображения и передаёт количество изображений в архиве переменной.

Усё работает:

for archive in $(cat $ARCH_LIST)
	do
		# Поиск FF-файлов в архиве

		FF_count=$(\
				tar \
					--list \
					--file=$archive \
					--wildcards "*.fits" | \
							tee /dev/tty | \
									wc --lines)

		if [ "$FF_count" -le "2" ]; then
			echo "Добавляем архив в список для удаления"
			echo $archive >> $RM_LIST
		else
			echo "Пропускаем архив"
		fi
	done

Нуно:

Сделать так чтобы on-fly сравнивалось количество найденных изображений с требуемым (более двух картинок):

То есть чтобы при чтении архива при превышении количества изображений более чем 2 шт. Чтение прекращалось и архив пропускался. А если количество меньше двух - добавлять архив в список на удаление.

Архивов около 6500, в каждом может быть порядка 100 изображений. Полная проверка занимает около суток.

А Модест устал ждать(((

Модест должен добавить кеширование

Модест должен с каждым .tgz архивом фоток держать .meta файл с описанием содержимого архива

У Модеста должно получиться что-то в духе

dir1/dir2/dir3 
   alice.tar.gz
   alice.tar.gz.meta
   bob.tar.gz
   bot.tar.gz.meta

В файле <name>.tar.gz.meta должны содержаться строчки в формате:

<filename.fits> md5sum
<filename2.fits> md5sum 

В этом случае Модесту нужно будет awk/grep/sed парсить .meta файлы и делать необходимые операции на лету.

Для этого модесту нужно добавить поддержку .meta файлов в свои кодец, но Модест HTML программист и ничего не поймет что я ему написал

gagarin0
()
Последнее исправление: gagarin0 (всего исправлений: 1)

А не надо работать с доисторическими технологиями. На более интересных инструментах всё элементарно решается:

(defn has-n-lins? [n start line]
  (if (= 0 n) true ;; нашли нужное количество файлов и остановились
      (let [end (str/index-of line "\n" start)] ;; нашли ещё одно вхождение и продолжили
        (when end (recur (dec n ) (inc end) line)))))

user> (->> "/tmp/enc/enc.tar" (shell {:out :string} "tar --list -f ") :out (has-n-lins? 2 0))
true
user> (->> "/tmp/enc/enc.tar" (shell {:out :string} "tar --list -f ") :out (has-n-lins? 22 0))
nil
ugoday ★★★★★
()
Ответ на: комментарий от gagarin0

Тут у меня оптимизируется часть, которая сначала пересчитывает все файлы, а потом сравнивает их количество с заданным пределом. Теоретически можно и это ускорить, но тут нужно свой tar --list писать, а это несколько многовато.

Без этого единственное серьёзное ускорение даст паралельная обработка архивов. Понятно, тут babashka тоже лучше баша.

ugoday ★★★★★
()
Ответ на: комментарий от ugoday

@vas199228, попробуйте для начала вот такую конструкцию

ВАЖНО тестируйте в изолированной песочнице!

cat ${ARCHI_LIST} | xargs -P$(nproc) -I% sh -c 'tar --list --file=% --wildcards "*.fits" | awk "(NR == 2) { print \"%\"; exit }"' | tee ${RM_LIST} 

Единственный момент, что «множество» запущенных параллельно процессов могут написать в stdout одновременно и получится «кашица», для этого нужно немного переделать скрипт:

cat ${ARCHI_LIST} | xargs -P$(nproc) -I% sh -c 'tar --list --file=% --wildcards "*.fits" | awk "(NR == 2) { exit 1 }" || echo % > %.rm' && find . -type f -iname "*.rm" -exec sh -c 'cat {}; rm {}' \; | tee ${RM_LIST}

@ugoday как это будет на барабашке?

gagarin0
()
Последнее исправление: gagarin0 (всего исправлений: 5)
Ответ на: комментарий от gagarin0
(defn has-n-files? [archive-file n]
"true если в архиве есть больше n файлов"
  (-> (shell {:out :string}
              "tar --list -f"
              archive-file)
       :out
       (str/split #"\n")
       count
       (> n)))

(->> archives  ;; по архивам
     (pmap #(when (has-n-files? % 2) %)) ;; параллельно пробегаемся
     (remove nil?)) ;; убираем негодные (последовательно, потому как всё одно быстро).

Ключевая функция тут pmap, которая как map только работает параллельно для каждого элемента коллекции, а потом склеивает результат.

ugoday ★★★★★
()
Ответ на: комментарий от gagarin0

В данном случае — никак, pmap стандартно использует количество ядер + 2 потока. А вообще, babashka — это clojure, который весь построен вокруг плясок с конкурентностью и паралелизмом, так что можно сделать что угодно, смотря где у нас тормоза, в диске или в цпу. Но это чуть больше кода, а для демонстрации pmap и выглядит кратко и разумное значение по умолчанию предоставляет.

ugoday ★★★★★
()
Ответ на: комментарий от ugoday

В данном случае — никак, pmap стандартно использует количество ядер + 2 потока

Это печально, это не позволяет использовать барабаршку в ряде случаев, когда нужно точно контролировать количество параллельных потоков

так что можно сделать что угодно

я так понимаю что лимитировать количество параллельных потоков можно, но нужны «специальные» упражнения

pmap и выглядит кратко и разумное значение по умолчанию предоставляет.

выглядит красиво, и выразительнее, но на условном, абстрактном, «удаленном хосте» барабашка проигрывает oneliner с xargs

gagarin0
()
Ответ на: комментарий от gagarin0

Вы забываете, что babashka — это гораздо более выразительный язык.

(defn my-pmap [f n coll]
  (let [rets (map #(future (f %)) coll)
        step (fn step [[x & xs :as vs] fs]
               (lazy-seq
                (if-let [s (seq fs)]
                  (cons (deref x) (step xs (rest s)))
                  (map deref vs))))]
    (step rets (drop n rets))))

И теперь у нас есть параллельное отображение, с точно контролируемым (параметр n) количеством исполнительных потоков. А захочется, можно использовать core.async чтобы асинхронно задачи по каналам гонять или напрямую использовать Java Executor Framework.

Собственно, недостаток и серьёзный у бабашки один, вытекающий из достоинств — нужна java машина для работы. Но раз уж у нас она уже есть, то ограничений в принципе никаких нет.

ugoday ★★★★★
()