Не спи - будь готов к труду и обороне!
Отвлечёмся на минуту и посмотрим, какие (вроде бы скучные) вещи происходят из тех “кусочков”, из которых и состоят алгоритмы. А “вкусности” (интеллектуальные, конечно!) заключаемся, в частности, в т.н. состоянии готовности отдельных операторов. Итак, программа (алгоритм) состоит из многих миллионов (и миллиардов) операторов (машинных команд – так нас учит Тюринг). Операнды возникают (причинно-следственные явления) как результат выполнения операций иными операторами.
Чем-то это мне начинает напоминать граф (в математическом понимании – где операторы соответствуют вершинам графа, а линии передачи данных – операнды и результаты выполнения операции – дугам графа), но явно сказать этого я пока боюсь…
На миниатюре выше как а) показан обычный оператор с двумя входными данными (операндами), на b) – первый из операндов показан (зеленым кружочком) готовым (значит, этот операнд имеет не случайное, а присвоенное значение), на c) – оба операнда готовы. Кстати, присвоенное значение может возникнуть как результате выполнения как другого (сверхсложного) оператора, так и в результате выполнения оператора простейшей инициализации (напр., a=1).
В реальности всё так и происходит – сначала оба операнда находятся в состоянии неготовности (на входах их операндов находятся какие-то случайный значения), потом один из них (на рисунке – 1-й) достигает состояния готовности (т.е. результат выполнения какого-то другого оператора поступает на 1-й вход данного), а потом то же происходит со вторым входом. При это говорят о готовности обоих (всех) операндов.
Что происходит после этого? Естественно, условие готовности всех операндов данного оператора по логической цепочке приводит к выполнению (срабатыванию) данного оператора и появлению на его выходе результата операции. “Логично!” – как гова́ривал известный актёр…
Но мы живём в реальном мире и понимаем, что каждое срабатывание оператора требует совершения некоторой работы. Не будем сейчас вспоминать о “пределе Ландауэра” - на изменение одного бита информации при комнатной температуре требуется 2,7×10^(-21) джоулей тепловой энергии - всё равно нам до этого предела довольно далеко, а величина этой работы довольно определённая - порядка 20×10^(-12) джоулей на каждую 64-битовую “плавающую” операцию при 28-нм кремниевой технологии. Но важное здесь, что операций-то производится много (миллионы миллионов миллионов – до 10^18). Поэтому операции (и время их выполнения и энергию надо экономить)..!
“Спи – тебе говорят!”
Однако давайте поразмыслим – в какой момент действительно требуется результат выполнения данной конкретной операции? Правильно – в тот момент, когда её результат будет востребован в качестве операнда какой-либо иной операции! Даже ежели оба операнда данной операции готовы будут, саму операцию ещё необязательно производить (ибо результат её выполнения ещё не востребован)… Из этих соображений были разработаны языки программирования с т.н. “ленивыми (lazy) переменными” (ибо результат операции логично ассоциируется с именами переменных). При этом выполнение конкретных операторов временно откладывается. В самом деле – если я (оператор) пока не нужен, почему бы мне по поры не поспать (полениться)… весьма здравое суждение!
“Вопрос на засыпку” – как электронные таблицы EXCEL (да и любые другие тоже) определяют корректную последовательность выполнения сложных (располагающихся во многих ячейках) выражений? Замечали ли Вы это явление? Думали ли Вы когда-нибудь над этим? Поделитесь своми соображениями…
Явную полезность приведённых соображений непросто оценить сразу и достойно – ведь идея отсрочки выполнения операторов означает вероятность повысить потенциальную возможность более равномерного по времени распределения (вариативность) загрузки поля параллельных вычислителей (а этого нам в большинстве случае нужно – “ресурсы превыше всего”); на рис. 5 период вариативности показан на стреле времени промежутком t1÷t2 (ну и, конечно, зелёным прямоугольником с соответствующий надписью). Конечно, если у нас имеются неограниченные вычислительные ресурсы (сколько угодно параллельных вычислителей), то все эти ухищрения ни к чему…
Не пройдёт и минимального времени, как мы эти особенности с пользою приме́ним (в публикации #014 при рассмотрении метода перемещения операторов по яруса́м ЯПФ)…… А какое применение Вы бы, Читатели, смогли найти применение такому качеству алгоритма, как "готовность к выполнению" операндов и самого оператора?
Удивительно жизненные рассуждения применимы к, казалось бы, предельно формализованным, отстранённым от жизненной суеты, ситуациям!.. Очень важно видеть и распознавать эти ситуации – много пользы такой подход приносит исследователю.