|
| 1 | +# Многопоточность |
| 2 | + |
| 3 | +Многопоточность – это свойство платформы (например, операционной системы, виртуальной машины и т. д.) или приложения, состоящее в том, что процесс, порождённый в операционной системе, может состоять из нескольких потоков, выполняющихся параллельно. Мы только начинаем знакомиться с многопоточностью и это домашнее задание будет не сложным. В нём не будет Java-кода. Мы проследим, как происходит параллельное выполнение операций на примере работы в командной оболочке. Вам нужно будет повторить описанные действия в терминале и изучить полученные результаты. |
| 4 | + |
| 5 | +Есть много таких задач, которые мы можем решить выполнять параллельно, например скачивание большого количества файлов, декодирование большого количества изображений. Конечно, все эти задачи можно решать и без использования распараллеливания. Но если мы обрабатываем каждый файл параллельно, мы можем получить большое преимущество с точки зрения скорости. В командной оболочке Bash есть несколько инструментов для распараллеливания, которые могут помочь нам в этом. |
| 6 | + |
| 7 | +## Ссылки |
| 8 | + |
| 9 | +* [Утилита GNU Parallel для параллельного выполнения](https://www.gnu.org/software/parallel/parallel_tutorial.html) |
| 10 | +* [Установка утилиты GNU Parallel в Ubuntu](https://onstartup.ru/utility/parallel/) |
| 11 | +* [Установка утилиты GNU Parallel в MacOS](https://formulae.brew.sh/formula/parallel) |
| 12 | + |
| 13 | +Сначала нам нужно создать скрипт, который мы будем выполнять параллельно. |
| 14 | + |
| 15 | +## Задачи |
| 16 | + |
| 17 | +* В файл `process` добавьте следующий код: |
| 18 | + |
| 19 | + ```bash |
| 20 | + echo "started processing $*.." |
| 21 | + sleep $((2+ RANDOM % 3)); |
| 22 | + echo finished processing "$*"; |
| 23 | + ``` |
| 24 | + |
| 25 | + Этот скрипт будет имитировать реальную обработку объёмного изображения. Его выполнение будет занимать от 2 до 5 секунд. В качестве аргумента программа будет принимать имя файла, который нужно обработать |
| 26 | + |
| 27 | +## Работа в терминале |
| 28 | + |
| 29 | +* Выполните этот скрипт у себя в терминале, чтобы проверить как он работает: |
| 30 | + |
| 31 | + ```bash |
| 32 | + ./process 1.jpg |
| 33 | + ``` |
| 34 | + |
| 35 | +Выполнение займет некоторое время. Программа не выполняет никаких полезных действий, только сигнализирует о начале и окончании своей работы. Вывод получится такой: |
| 36 | + |
| 37 | + ```bash |
| 38 | + started processing 1.jpg... |
| 39 | + finished processing 1.jpg |
| 40 | + ``` |
| 41 | + |
| 42 | +Базовый способ выполнять операции параллельно в Bash – это использование оператора `&`. Попробуем выполнить обработку двух изображений параллельно. |
| 43 | + |
| 44 | +* Выполните в терминале следующий код и изучите результат: |
| 45 | + |
| 46 | + ```bash |
| 47 | + ./process 1.jpg & ./process 2.jpg & wait |
| 48 | + ``` |
| 49 | + |
| 50 | + Обработка обоих файлов запустится примерно в одно и то же время и будет проходить параллельно. Поскольку время обработки случайное, вывод может получиться таким: |
| 51 | + |
| 52 | + ```bash |
| 53 | + started processing 2.jpg.. |
| 54 | + started processing 1.jpg.. |
| 55 | + finished processing 2.jpg |
| 56 | + finished processing 1.jpg |
| 57 | + ``` |
| 58 | + |
| 59 | + Обратите внимание, что выполнение обработки двух изображений началось практически одновременно. Использование команды `wait` заставит Bash дождаться окончания всех операций. |
| 60 | + |
| 61 | +Мы можем использовать этот подход для параллельной обработки нескольких изображений. Но если изображений много, например сотня, нам не нужно будет запускать обработку всех 100 изображений одновременно. Вместо этого лучше будет обрабатывать изображения партиями по несколько штук, чтобы эффективнее использовать ядра процессора. Наиболее продвинутым инструментом для параллельного запуска является утилита `Parallel`. |
| 62 | + |
| 63 | +* Используя пакетный менеджер своей ОС, установите утилиту GNU Parallel. |
| 64 | + |
| 65 | +* Скопируйте в терминал следующую команду: |
| 66 | + |
| 67 | + ```bash |
| 68 | + parallel --ungroup --jobs 3 ./process ::: 1 2 3 4 5 6 |
| 69 | + ``` |
| 70 | + |
| 71 | + Разберем эту команду подробнее. Опция `–ungroup` позволяет нам проследить процесс работы во время выполнения. Опция `--jobs` задаёт максимальное количество параллельно запущенных работ. Далее мы указываем нашу утилиту, которая будет выполняться параллельно. Через тройное двоеточие `:::` указываем список аргументов, которые будут переданы в утилиту. |
| 72 | + |
| 73 | +* Выполните команду и изучите получившийся результат. Вывод может получиться примерно такой: |
| 74 | + |
| 75 | + ``` sh |
| 76 | + started processing 1... |
| 77 | + started processing 2... |
| 78 | + started processing 3... |
| 79 | + finished processing 2 |
| 80 | + finished processing 3 |
| 81 | + started processing 4... |
| 82 | + started processing 5... |
| 83 | + finished processing 1 |
| 84 | + started processing 6... |
| 85 | + finished processing 4 |
| 86 | + finished processing 5 |
| 87 | + finished processing 6 |
| 88 | + ``` |
| 89 | + |
| 90 | + Так как мы указали максимальное количество задач в параллели 3, обработка первых трёх изображений началась практически одновременно. Обратите внимание, что утилита не дожидается окончания обработки всей партии из 3 изображений. Как только обработка второго и третьего закончилась, сразу запустилась обработка четвёртого и пятого, не дожидаясь окончания обработки первого. Это позволяет эффективно использовать ресурсы, так как мощности не простаивают в ожидании окончания обработки всей партии. |
| 91 | + |
| 92 | +Если максимальное количество одновременно запущенных работ не указывать, по умолчанию оно будет равно количеству ядер процессора. |
| 93 | + |
| 94 | +* Попробуйте запустить утилиту parallel без опции `--jobs` и проверьте, какое количество процессов у вас будет запущено параллельно: |
| 95 | + |
| 96 | + ```bash |
| 97 | + parallel --ungroup ./process ::: 1 2 3 4 5 6 7 8 9 10 |
| 98 | + ``` |
| 99 | + |
| 100 | + Вывод может получиться такой: |
| 101 | + |
| 102 | + ```bash |
| 103 | + started processing 1.. |
| 104 | + started processing 2.. |
| 105 | + started processing 3.. |
| 106 | + started processing 4.. |
| 107 | + started processing 5.. |
| 108 | + started processing 6.. |
| 109 | + started processing 7.. |
| 110 | + started processing 8.. |
| 111 | + finished processing 3 |
| 112 | + finished processing 5 |
| 113 | + started processing 9.. |
| 114 | + started processing 10.. |
| 115 | + finished processing 1 |
| 116 | + finished processing 4 |
| 117 | + finished processing 2 |
| 118 | + finished processing 6 |
| 119 | + finished processing 7 |
| 120 | + finished processing 8 |
| 121 | + finished processing 9 |
| 122 | + finished processing 10 |
| 123 | + ``` |
0 commit comments