Что такое дифференциальное исполнение? - PullRequest
23 голосов
/ 15 декабря 2010

Я наткнулся на вопрос переполнения стека, Как работает дифференциальное выполнение? , на который дан ОЧЕНЬ длинный и подробный ответ. Все это имело смысл ... но когда я закончил, я все еще не знал, что на самом деле представляет собой чертово дифференциальное выполнение. Что это на самом деле?

Ответы [ 2 ]

18 голосов
/ 22 июля 2014

перераб. Это моя N-я попытка объяснить это.

Предположим, у вас есть простая детерминированная процедура, которая выполняется многократно, всегда следуя одной и той же последовательности выполнения операторов или вызовов процедур. Вызовы процедуры сами записывают все, что они хотят, в FIFO последовательно, и они читают то же количество байтов с другого конца FIFO, например: **

enter image description here

Вызываемые процедуры используют FIFO в качестве памяти, потому что они читают то же, что и при предыдущем выполнении. Поэтому, если их аргументы в этот раз отличаются от прошлых раз, они могут это увидеть и сделать с этой информацией все, что захотят.

Чтобы начать, должно быть начальное выполнение, при котором происходит только запись, а не чтение. Симметрично, должно быть окончательное выполнение, при котором происходит только чтение, а не запись. Таким образом, существует регистр «глобального» режима, содержащий два бита: один для чтения и второй для записи, например:

enter image description here

Первоначальное выполнение выполняется в режиме 01 , поэтому выполняется только запись. Вызовы процедур могут видеть режим, поэтому они знают, что предшествующей истории нет. Если они хотят создавать объекты, они могут и помещают идентифицирующую информацию в FIFO (нет необходимости хранить в переменных).

Промежуточные исполнения выполняются в режиме 11 , поэтому происходит чтение и запись, а вызовы процедур могут обнаружить изменения данных. Если есть объекты, которые нужно обновлять, их идентификационная информация считывается и записывается в ФИФО, чтобы к ним можно было получить доступ и при необходимости изменить их.

Окончательное выполнение выполняется в режиме 10 , поэтому происходит только чтение. В этом режиме вызовы процедур знают, что они просто очищаются. Если какие-либо объекты поддерживаются, их идентификаторы считываются из FIFO и могут быть удалены.


Но реальные процедуры не всегда следуют одной и той же последовательности. Они содержат заявления IF (и другие способы варьирования того, что они делают). Как это можно сделать?

Ответ - это особый вид оператора IF (и его завершающего оператора ENDIF). Вот как это работает. Он записывает логическое значение своего тестового выражения и читает значение, которое тестовое выражение имело в прошлый раз. Таким образом, он может сказать, изменилось ли тестовое выражение, и принять меры. Для этого необходимо временно изменить регистр режима .

enter image description here

В частности, x - это предыдущее значение тестового выражения, считанное из FIFO (если чтение разрешено, иначе 0), а y - текущее значение теста выражение, записанное в FIFO (если запись включена). (На самом деле, если запись не включена, тестовое выражение даже не оценивается, и y равно 0.) Тогда x, y просто маскирует регистр режима r, w . Таким образом, если тестовое выражение изменило с True на False, тело выполняется в режиме только для чтения. И наоборот, если оно изменилось с False на True, тело выполняется в режиме только для записи. Если результат равен 00 , код внутри оператора IF..ENDIF пропускается. (Возможно, вы захотите немного подумать о том, охватывает ли это все случаи.)

Это может быть неочевидно, но эти операторы IF..ENDIF могут быть произвольно вложены, и их можно распространить на все другие виды условных операторов, таких как ELSE, SWITCH, WHILE, FOR и даже на вызов функций, основанных на указателе. Это также тот случай, когда процедуру можно разделить на подпроцедуры в любой желаемой степени, в том числе рекурсивной, при условии соблюдения режима.

(Существует правило, которое должно соблюдаться, называемое правило стирания , то есть в режиме 10 нет вычислений каких-либо последствий, таких как следование указателю или Индексирование массива должно быть сделано. Концептуально, причина в том, что режим 10 существует только с целью избавиться от вещей.)

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


Его использование в графических пользовательских интерфейсах позволяет поддерживать некоторый набор элементов управления или других объектов в соответствии с информацией о состоянии программы. Для этого использования три режима называются SHOW (01), UPDATE (11) и ERASE (10). Изначально процедура выполняется в режиме SHOW, в котором создаются элементы управления и соответствующая им информация заполняет FIFO. Затем выполняется любое количество выполнений в режиме ОБНОВЛЕНИЕ, где элементы управления изменяются по мере необходимости, чтобы оставаться в курсе состояния программы. Наконец, в режиме ERASE выполняется выполнение, при котором элементы управления удаляются из пользовательского интерфейса, а FIFO очищается.

enter image description here

Преимущество заключается в том, что после написания процедуры создания всех элементов управления в зависимости от состояния программы вам не нужно писать что-либо еще, чтобы сохранить ее. обновлен или убран позже. Все, что вам не нужно писать, означает меньше возможностей совершать ошибки. (Существует простой способ обработки событий пользовательского ввода без необходимости писать обработчики событий и создавать для них имена. Это объясняется в одном из видео, ссылки на которые приведены ниже.)

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

С точки зрения производительности, когда он создает, удаляет или изменяет элементы управления, он в любом случае тратит время. Когда он просто обновляет элементы управления, а изменений нет, циклы, необходимые для чтения, записи и сравнения, являются микроскопическими по сравнению с изменением элементов управления.

Другое соображение производительности и правильности, относительно систем, которые обновляют отображение в ответ на события, состоит в том, что такая система требует, чтобы на каждое событие отвечали, а не дважды, в противном случае отображение будет неправильным, даже если некоторые последовательности событий могут быть самоуничтожающимся. При дифференциальном выполнении проходы обновления могут выполняться так часто или редко, как требуется, и в конце прохода отображение всегда корректно.


Вот чрезвычайно сокращенный пример, где есть 4 кнопки, из которых кнопки 2 и 3 являются условными для логической переменной.

  1. На первом проходе в режиме Show логическое значение false, поэтому отображаются только кнопки 1 и 4.
  2. Затем для логического значения устанавливается значение true, и проход 2 выполняется в режиме обновления, в котором создаются кнопки 2 и 3, а кнопка 4 перемещается, давая тот же результат, как если бы логическое значение было истинным при первом проходе.
  3. Затем для логического значения устанавливается значение false, и этап 3 выполняется в режиме обновления, в результате чего кнопки 2 и 3 удаляются, а кнопка 4 возвращается на прежнее место.
  4. Наконец, проход 4 выполняется в режиме стирания, в результате чего все исчезает.

(В этом примере изменения отменяются в обратном порядке, как они были сделаны, но в этом нет необходимости. Изменения можно вносить и отменять в любом порядке.)

Обратите внимание, что в любое время FIFO, состоящий из соединенных вместе Старого и Нового, содержит в точности параметры видимых кнопок плюс логическое значение.

Смысл этого в том, чтобы показать, как можно использовать одну процедуру «рисования» без изменений для произвольного автоматического инкрементного обновления и удаления. Я надеюсь, что ясно, что это работает для произвольной глубины вызовов подпрограмм и произвольного вложения условий, включая циклы switch, while и for, вызов функций на основе указателей и т. Д. Если мне придется это объяснить, тогда я открыт для того, чтобы сделать объяснение слишком сложным.

enter image description here

Наконец, есть пара сырых, но коротких видео, размещенных здесь .

** Технически, они должны прочитать то же количество байтов, которое они написали в прошлый раз. Так, например, они могли написать строку, которой предшествует количество символов, и это нормально.


ДОБАВЛЕНО: Мне потребовалось много времени, чтобы убедиться, что это всегда будет работать. Я наконец доказал это. Он основан на свойстве Sync , что примерно означает, что в любой точке программы число байтов, записанных на предыдущем проходе, равно числу, считанному на последующем проходе. Идея доказательства заключается в том, чтобы сделать это индукцией по длине программы. Самым сложным для доказательства является случай раздела программы, состоящий из s1 , за которым следует IF (тест) s2 ENDIF , где s1 и s2 - это подразделы программы, каждый из которых удовлетворяет свойству Sync . Делать это только в тексте - это глазу на глаз, но здесь я попытался изобразить это: enter image description here

Он определяет свойство Sync и показывает количество байтов, записанных и прочитанных в каждой точке кода, и показывает, что они равны. Ключевые моменты заключаются в том, что 1) значение тестового выражения (0 или 1), считанное на текущем проходе, должно равняться значению, записанному на предыдущем проходе, и 2) условие Sync (s2) имеет вид довольный. Это удовлетворяет свойству Sync для объединенной программы.

9 голосов
/ 22 июля 2014

Я прочитал все, что смог найти, посмотрел видео и попробую описать основные принципы.

Обзор

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

Описание

Шаблон предполагает:

  1. A глобальная коллекция C объектов, которые нуждаются в периодических обновлениях .
  2. Семейство типов для тех объектов, где экземпляры имеют параметры.
  3. Набор операций на C:
    • Добавить A P - Поместить новый объект A в C с параметрами P.
    • Изменить A P - Изменить параметры объекта A в C на P.
    • Удалить A - Удалить объект A из C.
  4. Обновление C состоит из последовательности таких операций для преобразования C в заданную целевую коллекцию, скажем, C '.
  5. Учитывая текущую коллекцию C и цель C ', цель состоит в том, чтобы найти обновление с минимальными затратами. Каждая операция имеет стоимость единицы.
  6. Набор возможных коллекций описан на доменно-специфическом языке (DSL), который имеет следующие команды:
    • Создать A H - Создайте экземпляр объекта A, используя дополнительные подсказки H, и добавьте его в глобальное состояние. (Обратите внимание, здесь нет параметров.)
    • Если B, то T иное F - Условно выполнить последовательность команд T или F на основе булевой функции B, которая может зависеть от чего-либо в работающей программе.

Во всех примерах

  • Глобальное состояние - это экран или окно графического интерфейса.
  • Объекты являются виджетами пользовательского интерфейса. Типы: кнопка, выпадающий список, текстовое поле, ...
  • Параметры управляют внешним видом и поведением виджета.
  • Каждое обновление состоит из добавления, удаления и изменения (например, перемещения) любого количества виджетов в графическом интерфейсе.
  • Команды Create создают виджеты: кнопки, выпадающие списки, ...
  • Булевы функции зависят от основного состояния программы, включая состояние самих элементов управления GUI. Таким образом, изменение элемента управления может повлиять на экран.

Недостающие ссылки

Изобретатель никогда не заявляет об этом явно, но ключевая идея состоит в том, что мы запускаем интерпретатор DSL над программой, которая представляет все возможные целевые коллекции (экраны) каждый раз, когда мы ожидаем, что любая комбинация значений Булевой функции B изменилась. Интерпретатор выполняет грязную работу по приведению коллекции (экрана) в соответствие с новыми значениями B, создавая последовательность операций Add, Delete и Modify.

Существует последнее скрытое предположение: интерпретатор DSL включает в себя некоторый алгоритм, который может предоставлять параметры для операций добавления и изменения на основе истории созданий, выполненных до сих пор во время его текущего выполнения. В контексте GUI это алгоритм компоновки, а подсказки Create являются подсказками компоновки.

Изюминка

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

Дифференциальное выполнение - просто более разумная стратегия для интерпретатора. Это сводится к ведению сериализованной записи последнего исполнения переводчика. Это имеет смысл, потому что запись захватывает то, что в настоящее время на экране. Во время текущего запуска интерпретатор консультируется с записью, чтобы принять решение о том, как вызвать целевую коллекцию (конфигурация виджета) с операциями, имеющими наименьшую стоимость. Это сводится к тому, что мы никогда не удаляем объект (виджет), а добавляем его снова позже по цене 2. Вместо этого DE всегда будет модифицировать, что обойдется в 1. Если в некоторых случаях мы запускаем интерпретатор, когда значения B Если не изменено, алгоритм DE вообще не будет генерировать никаких операций: записанный поток уже представляет цель.

Когда интерпретатор выполняет команды, он также настраивает запись для своего следующего запуска.

Аналогичный алгоритм

Алгоритм имеет тот же вид, что и минимальное расстояние редактирования (MED). Однако DE - более простая проблема, чем MED, потому что в сериализованных строках исполнения DE нет «повторяющихся символов», как в MED. Это означает, что мы можем найти оптимальное решение с помощью простого онлайнового жадного алгоритма, а не динамического программирования. Это то, что делает алгоритм изобретателя.

Сильные

Я полагаю, что это хороший шаблон для реализации систем со многими сложными формами, в которых требуется полный контроль над размещением виджетов с помощью собственного алгоритма компоновки и / или логики «если еще» того, что видимое, глубоко вложено. Если в логике формы есть K гнезд "if elses" N, то есть K * 2 ^ N различных макетов, чтобы получить право. Традиционные системы проектирования форм (по крайней мере, те, которые я использовал) совсем не поддерживают большие значения K, N. Вы склоняетесь к большому количеству похожих макетов и специальной логике, чтобы выбрать их, которые уродливы и сложны в обслуживании. Этот шаблон DSL кажется способом избежать всего этого. В системах с достаточным количеством форм, чтобы компенсировать стоимость интерпретатора DSL, он даже будет дешевле при первоначальной реализации. Разделение интересов также является сильной стороной. Программы DSL абстрагируют содержание форм, в то время как интерпретатор является стратегией компоновки, действуя на основе подсказок DSL. Правильно подобрать дизайн DSL и подсказки макета кажется серьезной и интересной проблемой.

Сомнительный ...

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

Recap

Изобретатель до сих пор фокусировался на глубоких деталях того, как переводчик принимает свои решения. Это сбивает с толку, потому что это направлено на деревья, в то время как лес представляет больший интерес. Это описание леса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...