2024-08-31
|
@ -4,6 +4,7 @@
|
||||||
<a href='.'>.</a>
|
<a href='.'>.</a>
|
||||||
├─ <a href='archive'>archive</a>
|
├─ <a href='archive'>archive</a>
|
||||||
│ ├─ <a href='archive/README.md'>README.md</a>
|
│ ├─ <a href='archive/README.md'>README.md</a>
|
||||||
|
│ ├─ <a href='archive/parallelizing-bash-scripts.md'>parallelizing-bash-scripts.md</a>
|
||||||
│ └─ <a href='archive/round-robin.md'>round-robin.md</a>
|
│ └─ <a href='archive/round-robin.md'>round-robin.md</a>
|
||||||
├─ <a href='bash_scripts'>bash_scripts</a>
|
├─ <a href='bash_scripts'>bash_scripts</a>
|
||||||
│ ├─ <a href='bash_scripts/README.en.md'>README.en.md</a>
|
│ ├─ <a href='bash_scripts/README.en.md'>README.en.md</a>
|
||||||
|
@ -21,11 +22,8 @@
|
||||||
│ └─ <a href='bash_scripts/repo_orchestrate.sh'>repo_orchestrate.sh</a>
|
│ └─ <a href='bash_scripts/repo_orchestrate.sh'>repo_orchestrate.sh</a>
|
||||||
├─ <a href='pictures'>pictures</a>
|
├─ <a href='pictures'>pictures</a>
|
||||||
│ ├─ <a href='pictures/README.md'>README.md</a>
|
│ ├─ <a href='pictures/README.md'>README.md</a>
|
||||||
│ ├─ <a href='pictures/archive.jpg'>archive.jpg</a>
|
|
||||||
│ ├─ <a href='pictures/bash_scripts.jpg'>bash_scripts.jpg</a>
|
|
||||||
│ ├─ <a href='pictures/color-tomato-theme.jpg'>color-tomato-theme.jpg</a>
|
│ ├─ <a href='pictures/color-tomato-theme.jpg'>color-tomato-theme.jpg</a>
|
||||||
│ ├─ <a href='pictures/older-tomato-theme.jpg'>older-tomato-theme.jpg</a>
|
│ ├─ <a href='pictures/older-tomato-theme.jpg'>older-tomato-theme.jpg</a>
|
||||||
│ ├─ <a href='pictures/pictures.jpg'>pictures.jpg</a>
|
|
||||||
│ ├─ <a href='pictures/pomodoro.jpg'>pomodoro.jpg</a>
|
│ ├─ <a href='pictures/pomodoro.jpg'>pomodoro.jpg</a>
|
||||||
│ └─ <a href='pictures/website.jpg'>website.jpg</a>
|
│ └─ <a href='pictures/website.jpg'>website.jpg</a>
|
||||||
├─ <a href='.gitattributes'>.gitattributes</a>
|
├─ <a href='.gitattributes'>.gitattributes</a>
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
|
|
||||||
| Незавершённые публикации | Язык | Обновление |
|
| Незавершённые публикации | Язык | Обновление |
|
||||||
|:-----------------------------------------------------------|------|------------|
|
|:-----------------------------------------------------------------|------|------------|
|
||||||
| [Циклический алгоритм распределения задач](round-robin.md) | Java | 2023.06.05 |
|
| [Распараллеливание скриптов Bash](parallelizing-bash-scripts.md) | Bash | 2024.08.15 |
|
||||||
|
| [Циклический алгоритм распределения задач](round-robin.md) | Java | 2023.06.05 |
|
||||||
|
|
99
archive/parallelizing-bash-scripts.md
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
# Распараллеливание скриптов Bash
|
||||||
|
|
||||||
|
Примером последовательности действий, не зависящих друг от друга, могут быть — итерации циклов, или вызовы функций с
|
||||||
|
параметрами. Когда цикл один, или функция одна — это тривиальная задача для распараллеливания. Рассмотрим усложнённую
|
||||||
|
модель с тремя функциями и тремя параметрами для каждой — будем распараллеливать вызовы этих функций.
|
||||||
|
|
||||||
|
Сначала кодируем параметры в HEX коды и отбрасываем разделители строк — чтобы не заниматься экранированием спецсимволов.
|
||||||
|
Затем создаём массив строк — вызовы функций с параметрами. Далее выполняем эти строки в параллельном режиме с помощью
|
||||||
|
программы `xargs` — вызываем целевые функции командой `eval`. Внутри каждой функции сначала декодируем параметры
|
||||||
|
обратно и затем работаем с ними. Дополнительно для наглядности замеряем общее время выполнения функций.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
#---------------------------------------------------------------------------;
|
||||||
|
# три функции с тремя параметрами
|
||||||
|
#---------------------------------------------------------------------------;
|
||||||
|
# первая функция с тремя параметрами
|
||||||
|
function first_func {
|
||||||
|
p1="$(decode "$1")"
|
||||||
|
p2="$(decode "$2")"
|
||||||
|
p3="$(decode "$3")"
|
||||||
|
echo "1 ${FUNCNAME[*]} [$p1] [$p2] [$p3]"
|
||||||
|
sleep 5 # эмуляция работы 5 секунд
|
||||||
|
}
|
||||||
|
# вторая функция с тремя параметрами
|
||||||
|
function second_func {
|
||||||
|
p1="$(decode "$1")"
|
||||||
|
p2="$(decode "$2")"
|
||||||
|
p3="$(decode "$3")"
|
||||||
|
echo "2 ${FUNCNAME[*]} [$p1] [$p2] [$p3]"
|
||||||
|
sleep 5 # эмуляция работы 5 секунд
|
||||||
|
}
|
||||||
|
# третья функция с тремя параметрами
|
||||||
|
function third_func {
|
||||||
|
p1="$(decode "$1")"
|
||||||
|
p2="$(decode "$2")"
|
||||||
|
p3="$(decode "$3")"
|
||||||
|
echo "3 ${FUNCNAME[*]} [$p1] [$p2] [$p3]"
|
||||||
|
sleep 5 # эмуляция работы 5 секунд
|
||||||
|
}
|
||||||
|
#---------------------------------------------------------------------------;
|
||||||
|
# вспомогательные функции и экспорт для дочерних процессов
|
||||||
|
#---------------------------------------------------------------------------;
|
||||||
|
# удаление разделителей строк и кодирование символов в HEX коды
|
||||||
|
function encode { echo "$1" | tr -d '\r\n' | uni2ascii -aE -qps; }
|
||||||
|
# декодирование символов из HEX кодов и удаление разделителей строк
|
||||||
|
function decode { echo "$1" | ascii2uni -aE -q | tr -d '\r\n'; }
|
||||||
|
# перечисление используемых функций в дочерних процессах bash
|
||||||
|
export -f decode first_func second_func third_func
|
||||||
|
#---------------------------------------------------------------------------;
|
||||||
|
# подготовка массива строк и вывод строк массива
|
||||||
|
#---------------------------------------------------------------------------;
|
||||||
|
# параметры могут содержать любые печатные символы или быть пустыми
|
||||||
|
param0=" \$param\""
|
||||||
|
param1=
|
||||||
|
param2='"$2"!="$1"'
|
||||||
|
# кодирование параметров
|
||||||
|
p0="$(encode "$param0")"
|
||||||
|
p1="$(encode "$param1")"
|
||||||
|
p2="$(encode "$param2")"
|
||||||
|
# массив строк — вызовы функций с параметрами
|
||||||
|
array[0]="first_func '$p0' '$p1' '$p2'"
|
||||||
|
array[1]="second_func '$p2' '$p0' '$p1'"
|
||||||
|
array[2]="third_func '$p1' '$p2' '$p0'"
|
||||||
|
# вывод строк массива для наглядности
|
||||||
|
printf '%s\n' "${array[@]}"
|
||||||
|
#---------------------------------------------------------------------------;
|
||||||
|
# параллельный вызов функций и замер общего времени выполнения
|
||||||
|
#---------------------------------------------------------------------------;
|
||||||
|
# текущее время в миллисекундах
|
||||||
|
time_ms="$(date '+%s%3N')"
|
||||||
|
# вывод строк массива и вызов функции для каждой из них в параллельном режиме
|
||||||
|
printf '%s\0' "${array[@]}" | xargs -I{} -n1 -0 -P0 bash -c 'eval "{}"'
|
||||||
|
# время работы в миллисекундах
|
||||||
|
echo "Общее время выполнения: $(("$(date '+%s%3N')" - "$time_ms")) мс."
|
||||||
|
```
|
||||||
|
|
||||||
|
## Вывод
|
||||||
|
|
||||||
|
Строки массива, вызовы функций с параметрами через пробелы в кавычках
|
||||||
|
```
|
||||||
|
first_func 'U0020U0024U0070U0061U0072U0061U006DU0022' '' 'U0022U0024U0032U0022U0021U003DU0022U0024U0031U0022'
|
||||||
|
second_func 'U0022U0024U0032U0022U0021U003DU0022U0024U0031U0022' 'U0020U0024U0070U0061U0072U0061U006DU0022' ''
|
||||||
|
third_func '' 'U0022U0024U0032U0022U0021U003DU0022U0024U0031U0022' 'U0020U0024U0070U0061U0072U0061U006DU0022'
|
||||||
|
```
|
||||||
|
Параллельная работа функций, порядок может изменяться
|
||||||
|
```
|
||||||
|
3 third_func [] ["$2"!="$1"] [ $param"]
|
||||||
|
2 second_func ["$2"!="$1"] [ $param"] []
|
||||||
|
1 first_func [ $param"] [] ["$2"!="$1"]
|
||||||
|
```
|
||||||
|
Время работы функций в миллисекундах
|
||||||
|
```
|
||||||
|
Общее время выполнения: 5023 мс.
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
© Головин Г.Г., Код с комментариями, 2024
|
|
@ -2,9 +2,11 @@
|
||||||
echo "Удаление файлов и папок из каталогов проектов перед восстановлением архива."
|
echo "Удаление файлов и папок из каталогов проектов перед восстановлением архива."
|
||||||
echo "ОТМЕНА" && exit 0 # предохранитель
|
echo "ОТМЕНА" && exit 0 # предохранитель
|
||||||
cd ../.. # выходим из папки и из репозитория
|
cd ../.. # выходим из папки и из репозитория
|
||||||
# обходим все репозитории, расположенные на одном уровне с текущим
|
time_ms="$(date '+%s%3N')"
|
||||||
find . -mindepth 1 -maxdepth 1 -type d | sort -r | while read -r dir; do
|
# обход всех репозиториев, расположенных на одном уровне с текущим, кроме папки ".idea"
|
||||||
|
find . -mindepth 1 -maxdepth 1 -type d -not -name ".idea" | while read -r dir; do
|
||||||
echo "Обработка: $dir"
|
echo "Обработка: $dir"
|
||||||
# удаляем вложенные файлы и папки кроме папок ".git" и ".idea"
|
# внутри репозитория — удаление всех вложенных файлов и папок, кроме папки ".git"
|
||||||
find "$dir" -mindepth 1 -maxdepth 1 -type f,d -not -regex ".*\.git\|.*\.idea" -print0 | xargs -0 rm -r
|
find "$dir" -mindepth 1 -maxdepth 1 -type f,d -not -name ".git" -print0 | xargs -0 rm -r
|
||||||
done
|
done
|
||||||
|
echo "Общее время выполнения: $(("$(date '+%s%3N')" - "$time_ms")) мс."
|
||||||
|
|
|
@ -60,6 +60,6 @@ function tree_license {
|
||||||
export -f tree_license directory_tree list_directory_contents
|
export -f tree_license directory_tree list_directory_contents
|
||||||
cd ../.. # выходим из папки и из репозитория
|
cd ../.. # выходим из папки и из репозитория
|
||||||
time_ms="$(date '+%s%3N')"
|
time_ms="$(date '+%s%3N')"
|
||||||
# запуск параллельной обработки всех репозиториев, расположенных на одном уровне с текущим
|
# запуск параллельной обработки всех репозиториев, расположенных на одном уровне с текущим, кроме папки ".idea"
|
||||||
find . -mindepth 1 -maxdepth 1 -type d -print0 | xargs -I{} -n1 -0 -P0 bash -c 'tree_license "{}"'
|
find . -mindepth 1 -maxdepth 1 -type d -not -name ".idea" -print0 | xargs -I{} -n1 -0 -P0 bash -c 'tree_license "{}"'
|
||||||
echo "Общее время выполнения: $(("$(date '+%s%3N')" - "$time_ms")) мс."
|
echo "Общее время выполнения: $(("$(date '+%s%3N')" - "$time_ms")) мс."
|
||||||
|
|
|
@ -42,11 +42,11 @@ function compose {
|
||||||
description="Тема оформления / Старый помидор"
|
description="Тема оформления / Старый помидор"
|
||||||
fi
|
fi
|
||||||
wiki="" # оглавление по страницам вёб-сайта
|
wiki="" # оглавление по страницам вёб-сайта
|
||||||
if [ -f "$1/WIKI.md" ]; then
|
if [ -f "$dir/WIKI.md" ]; then
|
||||||
if [ "$remote" == "hub.mos.ru" ]; then
|
if [ "$remote" == "hub.mos.ru" ]; then
|
||||||
wiki="$(uni2ascii -a U -qpsn "$1/WIKI.md")"
|
wiki="$(uni2ascii -aU -qpsn "$dir/WIKI.md")"
|
||||||
else
|
else
|
||||||
wiki="$(basenc "$1/WIKI.md" --base64 -w0)"
|
wiki="$(basenc "$dir/WIKI.md" --base64 -w0)"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
# скрипт для создания удалённого репозитория
|
# скрипт для создания удалённого репозитория
|
||||||
|
@ -65,7 +65,7 @@ function compose {
|
||||||
echo "token=\"$(cat "$basedir/.token_gitea")\""
|
echo "token=\"$(cat "$basedir/.token_gitea")\""
|
||||||
cat "$basedir/repo_gitea.tmpl.sh"
|
cat "$basedir/repo_gitea.tmpl.sh"
|
||||||
fi
|
fi
|
||||||
} >"$1/.repo_remote.sh" && chmod +x "$1/.repo_remote.sh"
|
} >"$dir/.repo_remote.sh" && chmod +x "$dir/.repo_remote.sh"
|
||||||
# скрипт для создания локального репозитория
|
# скрипт для создания локального репозитория
|
||||||
{
|
{
|
||||||
echo "#!/bin/bash"
|
echo "#!/bin/bash"
|
||||||
|
@ -74,11 +74,11 @@ function compose {
|
||||||
echo "repo=\"$repo\""
|
echo "repo=\"$repo\""
|
||||||
echo "dir=\"$dir\""
|
echo "dir=\"$dir\""
|
||||||
cat "$basedir/repo_local.tmpl.sh"
|
cat "$basedir/repo_local.tmpl.sh"
|
||||||
} >"$1/.repo_local.sh" && chmod +x "$1/.repo_local.sh"
|
} >"$dir/.repo_local.sh" && chmod +x "$dir/.repo_local.sh"
|
||||||
}
|
}
|
||||||
export -f compose update_gitignore
|
export -f compose update_gitignore
|
||||||
cd ../.. # выходим из папки и из репозитория
|
cd ../.. # выходим из папки и из репозитория
|
||||||
time_ms="$(date '+%s%3N')"
|
time_ms="$(date '+%s%3N')"
|
||||||
# запуск параллельной обработки всех репозиториев, расположенных на одном уровне с текущим
|
# запуск параллельной обработки всех репозиториев, расположенных на одном уровне с текущим, кроме папки ".idea"
|
||||||
find . -mindepth 1 -maxdepth 1 -type d -print0 | xargs -I{} -n1 -0 -P0 bash -c 'compose "{}"'
|
find . -mindepth 1 -maxdepth 1 -type d -not -name ".idea" -print0 | xargs -I{} -n1 -0 -P0 bash -c 'compose "{}"'
|
||||||
echo "Общее время выполнения: $(("$(date '+%s%3N')" - "$time_ms")) мс."
|
echo "Общее время выполнения: $(("$(date '+%s%3N')" - "$time_ms")) мс."
|
||||||
|
|
|
@ -9,9 +9,3 @@
|
||||||
|  |
|
|  |
|
||||||
| website |
|
| website |
|
||||||
|  |
|
|  |
|
||||||
| bash_scripts |
|
|
||||||
|  |
|
|
||||||
| archive |
|
|
||||||
|  |
|
|
||||||
| pictures |
|
|
||||||
|  |
|
|
||||||
|
|
Before Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 3.9 KiB |