программисту гораздо большую степень гибкости по сравнению с использованием встроенных средств языка. Наряду с достоинствами, параллельное и распределенное программирование не лишено многих проблем, которые рассматриваются в следующей главе.
Проблемы параллельного и распределенного программирования
«Стремление обозначать точные значения любой физической величины (температура, плотность, напряженность потенциального поля или что-либо еще...) есть не что иное как смелая экстраполяция.»
В базовой последовательной модели программирования инструкции компьютерной программы выполняются поочередно. Программа выглядит как кулинарный рецепт, в соответствии с которым для каждого действия компьютера задан порядок и объемы используемых «ингредиентов». Разработчик программы разбивает основную задачу ПО на коллекцию подзадач. Все задачи выполняются по порядку, и каждая из них должна ожидать своей очереди. Все программы имеют начало, середину и конец. Разработчик представляет каждую программу в виде линейной последовательности задач. Эти задачи необязательно должны находиться в одном файле, но их следует связать между собой так, чтобы, если первая задача по какой-то причине не завершила свою работу, то вторая вообще не начинала выполнение. Другими словами, каждая задача, прежде чем приступить к своей работе, должна ожидать до тех пор, пока не получит результатов выполнения предыдущей. В последовательной модели зачастую устанавливается последовательная зависимость задач. Это означает, что задаче А необходимы результаты выполнения задачи В, а задаче В нужны результаты выполнения задачи С, которой требуется что-то от задачи D и т.д. Если при выполнении задачи В по какой-то причине произойдет сбой, задачи С и D никогда не п риступят к работе. В таком последовательном мире разработчик привычно ориентирует ПО сначала на выполнение действия 1, затем — действия 2, за которым должно следовать действие 3 и т.д. Подобная последовательная модель настолько закрепилась в процессе проектирования и разработки ПО, что многие программисты считают ее незыблемой и не допускают мысли о возможности иного положения вещей. Решение каждой проблемы, разработка каждого алгоритма и планирование каждой структуры данных — все это делалось с мыслью о последовательном доступе компьютера к каждой инструкции или ячейке данных.
Кардинальное изменение парадигмы
В мире параллельного программирования все обстоит по-другому. Здесь сразу несколько инструкций могут выполняться в один и тот же момент времени. Одна инструкция разбивается на несколько мелких частей, которые будут выполняться одновременно. Программа разбивается на множество параллельных задач. Программа может состоять из сотен или даже тысяч выполняющихся одновременно подпрограмм. В мире параллельного программирования последовательность и местоположение составляющих ПО не всегда предсказуемы. Несколько задач могут одновременно начать выполнение на любом процессоре без какой бы то ни было гарантии того, что задачи закреплены за определенными процессорами, или такая-то задача завершится первой, или все они завершатся в таком-то порядке. Помимо параллельного выполнения задач, здесь возможно параллельное выполнение частей (подзадач) одной задачи. В некоторых конфигурациях не исключена возможность выполнения подзадач на различных процессорах или даже различных компьютерах. На рис. 2.1 показаны три уровня параллелизма, которые могут присутствовать в одной компьютерной программе.
Модель программы, показанная на рис. 2.1, отражает кардинальное изменение парадигмы программирования, которая была характерна для «раннего» сознания программистов и разработчиков. Здесь отображены три уровня параллелизма и их распределение по нескольким процессорам. Сочетание этих трех уровней с базовыми параллельными конфигурациями процессоров показано на рис. 2.2.
Обратите внимание на то, что несколько задач может выполняться на одном процессоре даже при наличии в компьютере нескольких процессоров. Такая ситуация создается системными стратегиями планирования. На длительность выполнения задач, подзадач и инструкций оказывают влияние и выбранные стратегии планирования, и приоритеты процессов, и приоритеты потоков, и быстродействие устройств ввода-вывода. На рис. 2.2 следует обратить внимание на различные архитектуры, которые программист должен учитывать при переходе от последовательной модели программирования к параллельной. Основное различие в моделях состоит в переходе от строго упорядоченной последовательности задач к лишь частично упорядоченной (или вовсе неупорядоченной) коллекции задач. Параллелизм превращает ранее известные величины (порядок выполнения, время выполнения и место выполнения) в неизвестные. Любая комбинация этих неизвестных величин является причиной изменения значений программы, причем зачастую непредсказуемым образом.
Проблемы координации
Если программа содержит подпрограммы, которые могут выполняться параллельно, и эти подпрограммы совместно используют некоторые файлы, устройства или области памяти, то неизбежно возникают проблемы координации. Предположим, у нас есть программа поддержки электронного банка, которая позволяет снимать деньги со счета и класть их на депозит. Допустим, что эта программа разделена на три задачи (обозначим их А, В и С), которые могут выполняться параллельно.
Задача А получает запросы от задачи В на выполнение операций снятия денег со счета. Задача А также получает запросы от задачи С положить деньги на депозит. За-Дача А принимает запросы и обрабатывает их по принципу «первым пришел — первым обслужен». Предположим, на счете имеется 1000 долл., при этом