Uirh : другие произведения.

Лечение алкоголизма без ведома пациента

Самиздат: [Регистрация] [Найти] [Рейтинги] [Обсуждения] [Новинки] [Обзоры] [Помощь|Техвопросы]
Ссылки:


 Ваша оценка:
  • Аннотация:
    О том как выявить естественную параллельность алгоритма.

         ЛЕЧЕНИЕ АЛКОГОЛИЗМА БЕЗ ВЕДОМА ПАЦИЭНТА.

   Мир параллелен а вычислительные машины последовательны... Это
печально. Но не стоит слишком винить в этом машину - Мир чрезвычайно
сложен, машина относительно проста, но силится (вместе с программой)
изобразить из себя модель некоторого кусочка Мира. Так что
последовательность - плата за простоту. Однако как только мы сможем
делать более сложные машины - грех не сделать их более параллельными.
Так оно в общем то и происходит. Парралелизм на уровне совмещения
операций это уже давно пройденный этап. Парралелизм типа "выполнить одну
и то же действие со многими данными" - векторная машина, а так же
"выполнить над одним элементом данных последовательность действий" -
конвеерная машина - тоже довольно давно реализовано. К сожалению те и
другие хороши только для довольно узкого круга задач. Так что сейчас
интересна машина общего вида. Из самых общих соображений поятно, что она
должна состоять из множества одинаковых компонент, каждая из которых
сама по себе машина.
   Ну хорошо, возьмем множество процессоров, соединим их как-то между
собой... И что дальше? Полученную систему надо как то программировать.
Подавляющее большинство программистов пошлет нас, обратись мы к ним с
таким предложением, в хорошо известном нам направлении. Ну не умеют они
этого делать, да и откуда-бы? Да и вообще - слишком сложная задача. А
вот как бы сделать так, чтобы они не заметили, что пишут параллельные
программы? Кажется, такое средство есть. Причем оно уже довольно давно и
хорошо известно.

   Алгоритм, программа, вычислительный процесс - это модель некоторого
процесса в реальном мире, некоторого устройства, механизма. Да это
собственно и есть сам механизм. То, что в нем нет ни одной "железной"
детали (следует сказать что механизм "виртуальный") ничуть его не
портит. Он в точности так же способен взаимодействовать с другими
объектами, как виртуальными так и физическими, как если бы его заменили
на выполняющий те же функции гибрид будильника с паровозом, состоящий из
шестеренок, эксцентриков, кулачков, рычажков... были такие.
   Физический механизм, ну хоть тот же будильник, состоит из некоторого
числа деталей. Каждая из них - физический объект реального мира, простой
или состоящий из более мелких деталек. Алгоритм функционирования детали
содержится в ней самой - в её внешней форме, внутреннем устройстве...
(Ну конечно нельзя забывать и об окружении - вытащенная из будильника
шестеренка сама по себе годится разве что ребенку вместо волчка.)
Виртуальный механизм тоже состоит из деталей. Но алгоритмы их работы и
взаимодействия с соседями оторван от материала, из которого они
"сделаны", от данных тоесть, и оформлены в виде "программы". В
физическом механизме каждая шестеренка сама цепляет следующую, честно
сама поворачивается и пытается повернуть соседку, буде кто-то пытается
повернуть её саму. И аналогично все остальные детали одновременно и
постоянно выполняют заложенные в них алгоритмы. В виртуальном механизме
- не так. Работу деталей выполняет внешний "надзиратель". Процессор,
значит. Он обходит по некоторому маршруту все информационные детали и
производит для каждой некоторые действия, выполняя часть присущего
данной детальке алгоритма. Маршрут (алгоритм) обхода и алгоритмы работы
частей виртуального механизма заложены в программе, а программу написал
естественно программист...
   Ежели бы приставить к каждой детали виртуального механизма
собственный процессор, снабдить его алгоритмом работы оной детали - вот
тут и получился бы полный виртуальный аналог физического механизма,
столь же параллельный. (А то что виртуальный механизм скорее всего будет
состоять совсем из других деталей - это в сущности не важно.)
   Однако, коли мы имеем готовую последовательную программу, то выцепить
из нее нужные нам алгоритмы чрезвычайно сложно. В общем случае они
размазаны по всей программе и перемешаны между собой. Почти то же самое
относится и к самим деталям. Их конечно попроще выделить из единой
информационной структуры, размером со всю оперативную память... проще,
но не намного. Даже если мы захотим переделать программу для одного
исполнителя в программу для двух... (Ничего себе "даже"! - мало того что
надо выделить все нужные алгоритмы, так ведь еще следует соорудить два
алгоритма обхода, таких, чтобы исполнители не наступали друг другу на
пятки, а потом опять все сплавить между собой.) Вот как бы заставить
программистов не сооружть окрошку, а подавать все компоненты оного
кушанья по отдельности - каждая деталь отдельно, алгоритм ее работы -
тоже отдельно... а к ним еще сборочный чертёж...
   Кажется это можно сделать. Причем незаметно для программистов,
которые добровольно на это никогда не согласятся. Нам поможет эта самая
новомодная штучка - "объектное программирование".
   Ну, что там у нее за душой? Абстракции какие то - "объект",
"сообщение", "метод"... "Класс" вот еще вместе с каким-то
"наследованием", "инкапсуляция" - это когда никому не дают посмотреть
как объект из себя устроен - вот тоже слово придумали! Конечно, все эти
абстракции без должной конкретизации гроша ломаного не стоят. По сему
посмотрим, как они конкретизируются, ну хотя бы в Си++ и подобных ему
языках.

   "Объект" - та же самая Си-шная структура - кусок памяти, разделенный
для удобства на поля. "Класс" - коллекция, включающая описание оной
структуры и набор подпрограмм, умеющих делать с такими структурами что
то полезное. Эти в сущности совершенно обычные подпрограммы называются
"методами". "Инкапсуляция" - этакий забор вокруг "класса". За этот забор
информация о том как структура устроена не просачивается, в результате
никто находящийся снаружи внутрь такой структуры лазить не имеет права.
Как телевизор на гарантии и под пломбой - сломался - неси в гарантийную
мастерскую. Наружу из за забора инкапсуляции торчат только своего рода
веревочки. Дерни, значить, за веревочку - дверца и откроется... или там
закроется, или вдруг окрасится в зеленый цвет - за какую дернешь.
   Дерганье за веревочку как раз и называется "посылкой сообщения".
Причем говорят что "сообщение посылается объекту". Буде оная веревочка
другим концом привязана к подпрограмме, спрятанной за забором, то в Си++
все дубово: вызывается эта самая подпрограмма, а в качестве первого
аргумента ей передается тот самый объект (ну или ссылка на него). Мы
значит внутри объекта копаться не можем, правов видите ли не имеем, а
она имеет - ну пусть и копается. Применили понимаешь к абстрактному
объекту абстрактную операцию. Вооьбще то и в самом деле абстрактную - ну
чего мы про нее знаем - только название.
   Оные веревочки, конечно, снабжены табличками, указывающими какому
действию какая соответствует - именами подпрограмм - названиями
действий. И что в оном Си++ хорошо - так это то, что методы разных
классов, делающие (может быть вполне по-разному) сходные действия можно
называть одинаковыми именами. Даже нужно. Более того, две подпрограммы,
если они различаются хоть чем-то - типом возвращаемого значения,
количеством или типами аргументов - тоже можно называть одним и тем же
именем. Компилятор сам выберет нужную. (Это если все типы известны на
момент компиляции.) Это даже както называется, забыл как - както
по-дурацки. А ежели на момент компиляции тип объекта не известен, и
может быть ну не совсем любым, а одним из нескольких, специально
указанных - тогда компилятор внутрь всех таких объектов вставляет лишнее
поле, куда пишет номер типа, а в месте вызова подпрограммы вставляет
команды "по значению этого поля вызвать одну из нескольких подпрограмм"
- что то вроде "switch - case". Это явление тоже как-то специально
называется...

   Вот такая штука. Конечно, в результате компиляции появляется обычная
последовательная программа. Но в исходном тексте каждая деталь -
"объект" - описана отдельно, алгоритмы ее работы - "методы" - тоже
отдельно. Разве не этого мы добивались?
   Если честно сказать, по причинам не слишком понятным, программы,
сооруженные с помощью таких языков, чрезвычайно громоздки, пожирают
дикое количество ресурсов, компиляторы к ним гигантского размера и тоже
требуют массу ресурсов. И вообще, если Си - маленький, компактный и
очень простой язык, то Си++ - большой сложный и сильно избыточный.
Однако программировать на нем (если зазубрить все что полагается),
говорят намного легче, ибо он лучше соответствует стилю человеческого
мышления. Чтож, может быть. Это частично объясняет почему получаются
такие громоздкие программы: программировать легко, накладные расходы
незаметны - вот и включают в программу всё, что может понадобиться - в
первую очередь кучу интерфейса. Который весь написан таким же образом.
На Си писать ну тоже не сложно, хотя куда труднее, и главное на своей
шкуре чуствуешь что чего стоит. Ну и стараешься свести расход сил (своих
и машины) к минимуму, включая только то, что действительно нужно.

   Однако программисты незаметно для себя уже привыкли писать программы
разбитые на детали явным образом! Осталось подобрать выше указанным
абстракциям должную конкретизацию и их программы пойдут на
многопроцессорной машине... Стоп! Еще надо несколько ужесточить правила
языка. Зачем - сейчас будет видно.

   Вот предположим у нас есть несколько (довольно много) отдельных
машин, каждая с собственным процессором и памятью. Соединим их так,
чтобы стало возможно залезание в память других машин. (Возможно, хотя и
затруднительно - чтобы не злоупотребляли.)
   Начнем с объектов. Объект это ведь структура - кусок памяти -
последовательность полей разных типов. Нам надо чтобы объект целиком
размещался в памяти одной машины. Однако некоторые поля объекта могут
быть сами структурами, тоесть содержать в себе объекты, а те в свою
очередь - тоже. В результате можем заполучить такой объект, который ни в
какую память не влезет. Ну так запретить! Нехай поле объекта содержит
только простые значения. А буде там полагается быть объекту - в другое
место его, а в поле - ссылку.
   Методы. Если человек заболел - требуется доктор. А везти ли доктора к
больному или больного к доктору - можно по разному. Лишь бы метод и
объект оказались в одной памяти одновременно. Однако, если подпрограмме
разрешить обращаться к нескольким объектам одновременно - имеем
возможность заполучить неприятности. Например проблема выделения и
доставки друзей и родственников больного. Запретить! Друзей и
родственников в операционную не пущать! Только врач и пациэнт! (Имеются
в виду так называемые "дружественные" функции...) А буде по ходу
алгоритма доктору (то бишь методу) надо сделать что либо с другими
объектами (теми, что были в полях данного) - пишите письма! Тоесть
посылайте сообщения - эти объекты сейчас в других местах, пусть ими
занимается кто нибудь другой. Да, кстати - никаких самомодефицирующихся
программ! И вообще - писать в программу нельзя, ее можно только
выполнять. Тогда к каждому пациэнту можно направить собственную копию
метода. А когда она отработает - стереть без зазрения совести (только
оригинал не трогать). Или, если есть возможность, подержать некоторое
время - вдруг еще раз понадобится. Никаких глобальных переменных - вам
что, объектов не хватает?! (Они же и так все глобальные, а если кто
завел локальный объект - ему самому придется заботиться о его
уничтожении при выходе из области локализации.) И никаких статических
переменных у подпрограмм! Ну тоесть конечно последнее можно бы и
разрешить. Только тогда этот метод на всю жизнь будет обречен пасти свои
статические переменные, пребывая в одном экземпляре. И придется таскать
всех пациэнтов к нему. (Впрочем в некоторых случаях такое свойство может
даже и пригодится.)
   И наконец самое интересное - посылка сообщений. Там она сводилась к
вызову подпрограммы. И хочешь-не хочешь - ожидай её завершения.
Процессор то один, и память одна, вот и вычисляются они на одном стэке.
Но здесь то памяти разные! Посему посылка сообщения это не просто
обращение к подпрограмме. Надобно во первых найти объект-адресат, во
вторых найти ближайшую к нему копию метода, в третьих озаботиться чтобы
они оказались в одной памяти, доставить туда же список аргументов,
передаваемых оной подпрограмме, выделить там кусок места под ее
локальные переменные, и наконец в пятых - велеть тамошнему процессору
выполнять эту подпрограмму. Другими словами надо создать новый процесс.
Теперь этот процесс будет выполняться паралельно с тем, что послал
сообщение.
   Все это конечно хорошо, но может оказаться так, что вызвавши
подпрограмму (которая неожиданно превратилась в процесс, параллельный
данному), он (кто вызвал) будет дожидаться результата ее деятельности.
Глобальные переменные мы запретили, всяческие побочные эффекты
запретили, передачи параметров "по имени" у нас и небыло - осталось
ждать значение, возвращаемое подпрограммой-функцией. Запретить функциям
возвращать значения было бы совершенно непорядочно. Ладно, возвратим
значение. Причем не когда тот процесс закончит свою работу и выдаст
результат, а сразу - как только он породился. Это будет значение
специального вида. Если данная программа засунет его в переменную и на
этом успокоится, а потом может вообще потеряет - ну и ладно. А вот как
только она попытается сделать с ним что либо содержательное - тут ей
придется подождать, пока действительно не закончится тот процесс и не
выдаст настоящее значение.
   А каким образом это специательное, фиктивное в общем то значение
заменяется на настоящее, как производится разыскание объекта, а так же
метода (буде их можно перетаскивать из одной памяти в другую), что такое
наследование, чем грозит ограничение адресного пространства горизонтом и
как заставить процессы не наступать друг другу на пятки (ну это просто -
семафоры) - это мы обсудим как нибудь в другой раз.

   Итак (резюме, значит) объектные языки программирования, если их
малость почистить, склоняют программиста описывать каждую информационную
деталь сооружаемой им системы в отдельности. Этим можно воспользоваться,
заставив эмулировать каждую деталь отдельный процессор, тем самым
загрузив работой одновременно много процессоров. А это и есть
распараллеливание программ, хотя программист об этом возможно даже и не
догадался. 

 Ваша оценка:

Связаться с программистом сайта.

Новые книги авторов СИ, вышедшие из печати:
О.Болдырева "Крадуш. Чужие души" М.Николаев "Вторжение на Землю"

Как попасть в этoт список
Сайт - "Художники" .. || .. Доска об'явлений "Книги"