Характеристики оперативной памяти и особенности ее устройства являются важнейшим фактором, от которого зависит быстродействие компьютера. Ведь даже при наличии быстрого процессора скорость выборки данных из памяти может оказаться невысокой, и именно эта невысокая скорость работы с оперативной памятью будет определять быстродействие компьютера. Время цикла работы с памятью tm обычно заметно больше, чем время цикла центрального процессора tc. Если процессор инициализирует обращение к памяти, она будет занята в течение времени tc+tm и в течение этого промежутка времени ни одно другое устройство, в том числе и сам процессор, не смогут работать с оперативной памятью. Таким образом, возникает проблема доступа к памяти.
Эта проблема решается специальной организацией оперативной памяти. Принята следующая классификация параллельных компьютеров по архитектуре подсистем оперативной памяти: системы с разделяемой памятью, у которых имеется одна большая виртуальная память и все процессоры имеют одинаковый доступ к данным и командам, хранящимся в этой памяти; системы с распределенной памятью, у которых каждый процессор имеет свою локальную оперативную память и к этой памяти у других процессоров нет доступа.
Для программиста часто бывает важно знать тип оперативной памяти компьютера, на котором он работает. Ведь архитектура памяти определяет способ взаимодействия между различными частями параллельной программы. На компьютере с распределенной памятью программа перемножения матриц, например, должна создать копии перемножаемых матриц на каждом процессоре, что технически осуществляется передачей на эти процессоры сообщения, содержащего необходимые данные. В случае системы с разделяемой памятью достаточно лишь один раз задать соответствующую структуру данных и разместить ее в оперативной памяти. Остановимся подробнее на раличных архитектурах подсистемы памяти.
Простейший способ создать многопроцессорный вычислительный комплекс с разделяемой памятью - взять несколько процессоров, соединить их с общей шиной и соединить эту шину с оперативной памятью. Этот простой способ является не очень удачным, поскольку между процессорами возникает борьба за доступ к шине, и если один процессор принимает команду или передает данные, все остальные процессоры вынуждены будут перейти в режим ожидания. Это приводит к тому, что начиная с некоторого числа процессоров, быстродействие такой системы перестанет увеличиваться при добавлении нового процессора.
Несколько улучшить картину может применение кэш-памяти для хранения команд. При наличии локальной, то есть принадлежащей данному процессору, кэш-памяти, следующая необходимая ему команда с большой вероятностью будет находиться в кэш-памяти. В результате этого уменьшается количество обращений к шине, и быстродействие системы возрастает. Вместе с тем возникает новая проблема - проблема кэш-когерентности. Эта проблема заключается в том, что если, скажем, двум процессорам для выполнения различных операций понадобилось значение V, это значение будет храниться в виде двух копий в кэш-памяти обоих процессоров. Один из процессоров может изменить это значение в результате выполнения своей команды, и оно будет передано в оперативную память компьютера. Но в кэш-памяти второго процессора все еще хранится старое значение! Следовательно, необходимо обеспечить своевременное обновление данных в кэш-памяти всех процессоров компьютера.
Имеются и другие реализации разделяемой памяти. Это, например, разделяемая память с дискретными модулями памяти. Физическая память состоит из нескольких модулей, хотя виртуальное адресное пространство остается общим. Вместо общей шины в этом случае используется переключатель, направляющий запросы от процессора к памяти. Такой переключатель может одновременно обрабатывать несколько запросов к памяти, поэтому, если все процессоры обращаются к разным модулям памяти, быстродействие возрастает.
В вычислительных системах с распределенной памятью оперативная память имеется у каждого процессора. Процессор имеет доступ только к своей памяти. В этом случае отпадает необходимость в шине или переключателе. Нет и конфликтов по доступу к памяти, так как каждый процессор работает только со своей собственной памятью. Нет присущих системам с разделяемой памятью ограничений на число процессоров, нет, разумеется, и проблемы с кэш-когерентностью. Но, с другой стороны, возникают проблемы с организацией обмена данными между процессорами. Обычно такой обмен осуществляется при помощи обмена сообщениями-посылками, содержащими данные. Для формирования такой посылки требуется время, для получения и считывания полученных данных тоже необходимо определенное время. Эти дополнительные затраты времени – плата за все те преимущества, о которых шла речь.
Программирование для систем с распределенной памятью – более сложная задача. Оно требует разбиения исходной вычислительной задачи на подзадачи, выполнение которых может быть разнесено на разные процессоры.