Multitasking
- Мой небольшой конспект, собранный из разных источников, для повторения темы, как устроена многозадачность, конкурентные и параллельные вычисления
Последовательное выполнение | Serial computing
При последовательном выполнении, задачи выполняются друг за другом и чтобы приступить к обработке следующей задачи, нужно дождаться завершения предыдущей.
Конкурентное выполнение | Concurrent computing
Под конкурентным выполнением можно понимать выполнение нескольких задач с конкуренцией (соперничеством) между собой за доступ к вычислительным ресурсам.
Потоки и процессы конкурируют друг с другом за доступ к ядру. По одному потоку на ядро.
Операционная система или другая среда выполнения при помощи планировщика будет переключать ядра, чтобы тот или иной поток выполнил свои инструкции. Время этих переключений настолько мало, что складывается ощущение параллельного выполнения.
Конкурентное выполнение задач больше относится к многозадачности системы. Когда в одно и тоже время могут быть запущены множество процессов.
Конкурентное выполнение не требует наличия нескольких ядер или процессоров.
Асинхронное выполнение
При работе с задачами завязанными на ввод и вывод информации (запись и чтение, запрос и ответ) возникают блокирующие операции — операция которая требует некоторого ожидания до получения результата. Это происходит из-за того, что инструкции для вычисления чего-либо передаются на другое устройство — другой сервер, диск, оперативная память, база данных и тд.
Разделение задачи связанной с вводом и выводом данных на подзадачи и переключение между ними, после возникновения блокирующей операции, не дожидаясь ее окончания, называется асинхронным выполнением.
Реализация асинхронного выполнения называется асинхронным программированием.
Асинхронное выполнение происходит в одном процессе и в одном потоке.
Для реализации асинхронного выполнения задач связанных с вводом и выводом информации используют сопрограммы (корутины) и событийный цикл (event loop).
Цикл событий опрашивает каждую корутину, в каком состоянии она сейчас находится. Если корутина простаивает (находится в режиме ожидания ввода-вывода), чтобы не блокировать выполнение задачи, цикл событий переключает действие на другую корутину. В результате не происходит блокирование выполнения программы.
Параллельное выполнение | Parallel computing
В свою очередь параллельное выполнение подразумевает обязательное наличие более одного вычислительного устройства (процессора или ядра), которые будут одновременно выполнять несколько задач.
Обычно одна задача разбивается на несколько связанных подзадач, которые одновременно и независимо друг от друга выполняются на разных ядрах. Затем их результаты объединяются в один.
При параллельном выполнении количество подзадач не может быть больше количества ядер.
Параллельное выполнение реализуется в многоядерных и многопроцессорных системах для повышения производительности и пропускной способности программных компонентов.
Распределенное выполнение | Distributed computing
Несколько компьютеров образуют распределенную систему. У каждой машины своя память и вычислительные ресурсы. Компьютеры выполняют одни и те же задачи, при этом обмениваясь данными через сеть.
Многозадачность | Multitasking
Многозадачность — свойство операционной системы или другой среды выполнения, которое позволяет конкурентно обрабатывать несколько задач.
- у каждого приложения есть как минимум один процесс, а у каждого процесса — минимум один поток, который называют главным и из него при необходимости запускают новые. Процесс и поток взаимоисключающие определения. Без одного не бывает другого.
- для достижения многозадачности не требуется параллельного выполнения.
- Scheduler — планировщик операционной системы, который управляет потоками и процессами.
Операционная система реализует многозадачность по-разному:
-
для CPU-bound используется так называемая приоритетная многозадачность. В этом случае планировщик операционной системы решает, когда и в какой момент времени переключить первую задачу на другую (переключить контекст). При решении учитывается приоритет задачи, который может динамически изменяться.
-
для I/O-bound операций используется кооперативная многозадачность, при которой следующая задача начинает выполняться после того, как текущая задача переходит в состоянии блокировки (или простоя).
Многозадачность на основе процессов
Процесс — экземпляр программы, который хранится в оперативной памяти (RAM) и выполняется с помощью одного или нескольких потоков.
Обладает собственным адресным пространством — область памяти, где хранятся данные и переменные, необходимые для выполнения программы.
Процессы обособлены. Процессы работают каждый со своими данными — обмениваться чем-то они могут только через механизм межпроцессного взаимодействия.
Создание и завершение процессов обходится "дороже" из-за необходимости захвата и освобождения ресурсов.
Переключение процессов также дорогостоящая операция, так как включает в себя уже не только переключение контекста.
Каждый процесс имеет уникальный идентификатор, который позволяет операционной системе управлять этим процессом.
Операционная система использует процессы для разделения исполняемых приложений.
Процессы никак не связаны между собой и могут принадлежать даже различным пользователям, разделяющим одну вычислительную систему.
Разделение программ на процессы в отличие от потоков преследует цель не в скорости, а в безопасности.
В качестве примера можно привести браузер. Каждая вкладка браузера — это отдельный процесс. Процессы изолированы операционной системой, а значит если страница вкладки в браузере выйдет из строя это не приведет к проблемам у других открытых вкладок. В целом это позволяет избегать много проблем с безопасностью, т.к. ресурсы и адресное пространство не разделяются между процессами.
Многозадачность на основе потоков
Многопоточность — свойство операционной системы или другой среды выполнения, которая помогает достичь более эффективного использования вычислительных ресурсов процессора, путем создания нескольких потоков внутри одного процесса.
Поток — программный компонент (часть процесса, unit of execution), которая выполняет инструкции программы на ядре процессора.
Потоки выполняются в процессе. Они используют общее адресное пространство процесса и имеют общий доступ к его ресурсам, таким как память, файловые дескрипторы и т.д.
Каждый поток имеет свой уникальный идентификатор, который позволяет операционной системе управлять им.
Потоки не имеют собственных ресурсов, они используют память, выделенную под процесс, и поэтому потоки создаются и завершаются быстрее: системе не нужно каждый раз выделять новое адресное пространство, а после высвобождать его. Переключение потоков также относительно дешево: для этого требуется лишь переключение контекста.
Планирование, состояния потоков, приоритеты Выбор текущего потока из нескольких активных потоков, пытающихся получить доступ к процессору называется планированием. Процедура планирования обычно связана с весьма затратной процедурой диспетчеризации — переключением процессора на новый поток, поэтому планировщик должен заботиться об эффективном использовании процессора.
Поток может находиться в одном из трёх состояний:
-
Выполняемый (Executing) — поток, который выполняется в текущий момент на процессоре.
-
Готовый (Runable) — поток ждет получения кванта времени и готов выполнять назначенные ему инструкции. Планировщик выбирает следующий поток для выполнения только из готовых потоков.
-
Ожидающий (Waiting) — работа потока заблокирована в ожидании завершения блокирующей операции.
Для выполнения потока операционная система выделяет время процессора. При этом каждому потоку назначается приоритет выполнения.
У каждого потока есть числовое значение приоритета. Если есть несколько спящих потоков, которые нужно запустить, то операционная система сначала запустит поток с более высоким приоритетом.
Система управляет потоками так, как считает нужным. Потоки с низким приоритетом не будут простаивать, просто они будут получать меньше времени, чем другие, но выполняться все равно будут.
Потоки с одинаковыми приоритетами запускаются в порядке очереди.
Приоритет потока может меняться в процессе выполнения
Почему нужна поддержка множества потоков внутри одного процесса?
В случае, когда одна программа выполняет множество задач, поддержка множества потоков внутри одного процесса позволяет:
- Разделить ответственность за разные задачи между разными потоками
- Повысить быстродействие
Кроме того, часто задачам необходимо обмениваться данными, использовать общие данные или результаты других задач. Такую возможность предоставляют потоки внутри процесса, так как они используют адресное пространство процесса, которому принадлежат. Конечно, можно было бы создать под разные задачи дополнительные процессы, но:
- у процесса будет отдельное адресное пространство и данные, что затрудняет взаимодействие частей программы
- создание и уничтожение процесса дороже, чем создание потока
Например, основной поток отвечает за элементы пользовательского интерфейса и реагирует на действия пользователя. Дополнительные рабочие потоки используются для выполнения длительных расчетных операций, которые, в противном случае будут занимать основной поток, в результате чего пользовательский интерфейс будет недоступен. Для сетевых запросов, запросов к базам данным также могут использоваться дополнительные потоки.
