Возврат на сайт Назад Оглавление


7. ЗАКЛЮЧИТЕЛЬНЫЕ ЗАМЕЧАНИЯ

В литературе иногда проводят отчетливое различие между "параллельным программированием" - обработка одного задания с помощью нескольких центральных процессоров - и "мультипрограммированием" - разделение времени центрального процессора между различными заданиями. Я всегда считал, что это различие довольно искусственное и поэтому способно подчас вызвать путаницу. С общей точки зрения мы имеем в обоих случаях несколько последовательных процессов, которые должны взаимодействовать друг с другом, и наши обсуждения такого взаимодействия в равной степени относятся как к "параллельному программированию", так и к "мультипрограммированию", а также и к любой их комбинации. Если в параллельном программировании речь идет о распределении оборудования, то в мультипрограммировании - о распределении времени; и то и другое - различные реализации одной логической структуры, и я считаю, что развитие средств для описания и построения таких структур само по себе, т.е. независимо от различий в реализации, является одним из основных результатов работы, на основе которой возникла эта глава. В качестве конкретного примера такой унификации взгляда на вещи мне хотелось бы упомянуть о полной симметрии между обычной последовательной вычислительной машиной, с одной стороны, и ее периферийным устройством - с другой (что отражено, например, в ╖4.3 "Ограниченный буфер").

Наконец, я хочу еще раз выразить свое отношение к вопросу о корректности программ, так как не очень уверен, что все оказанное об этом ранее прозвучало достаточно ясно и убедительно.

Если я предлагаю методы, с помощью которых мы могли бы достигнуть большей уверенности в правильности наших построений, то это, конечно, скорее психология, чем математика. Я чувствую, что человеческий разум чрезвычайно неприспособлен мыслить в категориях развивающегося во времени процесса, и в этом случае нашим сильнейшим средством для оперирования этими понятиями является придание определенного смысла значениям соответствующих величин. Например, глядя на программу:

       i := 10;
LO:    x := sqrt(x); i := i - 1;
       if i > 0 then goto L0
мы заключаем, что операция "x := sqrt(x)" повторяется десять раз, и у меня создается впечатление, что мы делаем такое заключение, придавая "i" следующий смысл: число раз, которое еще должна быть повторена операция "x := sqrt(x)". Но нам следует сознавать, что такая, не связанная с временем трактовка, не является постоянно верной при течении процесса: немедленно за выполнением "x := sqrt(x)", но еще до выполнения следующего оператора "i := i - 1" значение "i" на единицу больше того числа раз, какое еще должна быть повторена операция "x := sqrt(x)". Иначе говоря, мы должны указать, на каких стадиях протекания процесса такой смысл применим, и, конечно, он должен иметь силу в каждой ситуации, где мы полагаемся на этот смысл в рассуждениях, убеждающих нас в том, что программа в целом выполняется желаемым образом.

При полностью последовательном программировании, как в приведенном примере, области применения такого смысла обычно тесно связаны с определенными местами в тексте программы (если это не так, то мы просто имеем мудреную и беспорядочно составленную программу). При параллельном программировании мы видели, в частности в п.5.2.1, что сознательное построение таких "областей применимости смысла" является стоящим делом. Признание иерархического различия между наличием сообщения и самим сообщением, что здесь было вынужденным делом, может служить средством более ясного понимания даже при не параллельном программировании.

Например, если я женат на одной из десяти женщин, пронумерованных от 1 до 10, то этот факт можно представить значением связанной со мной переменной "номер женщины". Если же я холост, то обычным программистским приемом было бы представление статуса холостяка одиннадцатым значением той же переменной, скажем "номер женщины = 0". Смысл значения этой переменной теперь таков: "Если номер моей жены равен 0, то я холост; если он отличен от нуля, то указывает номер моей жены". Вывод таков, что введение отдельной булевой переменной "женат" может быть более правильным.

Мы знаем, что сила и гибкость машин фон Неймана основана на том, что они трактуют все слова в машине одинаковым образом. Часто еще недопонимается, что вследствие этого пользователю приходится строить такую структуру, которая всегда должна быть распознаваемой.

Обычно в качестве обоснования достоинств машин фон Неймана называют то, что они могут изменять собственные команды; однако большинство современных алгоритмических трансляторов строят объектные программы, которые во все время выполнения остаются так же неизменны, как и первоначальный текст. Вместо хаотической модификации своих собственных команд до или после их выполнения создание и выполнение этих команд происходит в различные последовательные стадии: фаза трансляции и фаза выполнения. И это всем нам на пользу.

Я твердо убежден, что в каждом процессе любой сложности встречающиеся переменные допускают аналогичное иерархическое упорядочивание и что если эти уровни иерархии легко распознаются в тексте программы, то выигрыш в наглядности программы и в эффективности реализации будет значительным. Отмечу еще, что если из этой главы читатель получил более ясное представление о том, какой признак упорядоченности является в том или ином случае наиболее подходящим, то я достиг одной из своих целей. И, кроме того, разве мы не можем надеяться, что сопоставление со сложностями Мультипрограммирования даст нам более ясное понимание о не параллельном программировании как таковом?


Возврат на сайт Назад Оглавление