Ремонт принтеров, сканнеров, факсов и остальной офисной техники


назад Оглавление вперед




[106]

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

Теперь мы видим, что потоки дают альтернативный способ моделирования объектов, обладающих внутренним состоянием. Можно моделировать изменяющуюся величину, например, внутреннее состояние какого-либо объекта, через поток, который представляет динамику изменений состояния. В сущности, с помощью потоков мы представляем время явно, так что время в моделируемом мире оказывается отделено от последовательности событий, происходящих во время вычисления. Действительно, благодаря наличию delay между имитируемым временем модели и последовательностью событий при вычислении может быть весьма мало общего.

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

(define (make-simplified-withdraw balance) (lambda (amount)

(set! balance (- balance amount)) balance))

Вызовы make-simplified-withdraw порождают вычислительные объекты, и каждый из них содержит внутреннюю переменную balance, которая уменьшается при каждом обращении к объекту. Этот объект принимает в качестве аргумента количество денег amount, а возвращает новый баланс. Можно представить себе, как пользователь банковского счета печатает последовательность входных данных для такого объекта и рассматривает на экране дисплея последовательность возвращаемых данных.

С другой стороны, можно смоделировать обработчик снятия денег и в виде процедуры, которая принимает на входе баланс и поток снимаемых сумм, а порождает поток последовательных балансов на счету:

(define (stream-withdraw balance amount-stream) (cons-stream balance

(stream-withdraw (- balance (stream-car amount-stream)) (stream-cdr amount-stream))))

Stream-withdraw реализует хорошо определенную математическую функцию, выход которой полностью определяется входом. Однако предположим, что вход amount-stream есть поток последовательных значений, вводимых пользователем, и что получающийся поток балансов выводится на печать. В таком случае, с точки зрения пользователя, который печатает значения и смотрит на результаты, потоковый процесс обладает тем же поведением, что и объект, созданный при помощи make-simplified-withdraw. Однако в потоковой версии нет ни присваивания, ни внутренней переменной состояния, и, следовательно, она не вызывает никаких теоретических сложностей из описанных в разделе 3.1.3. И все-таки система обладает состоянием!


запросы Петра

слияние

банковский счет

запросы Павла

Рис. 3.38: Совместный банковский счет, смоделированный через слияние двух потоков событий-транзакций.

Это достижение достойно внимания. Несмотря на то, что stream-withdraw реализует хорошо определенную математическую функцию, поведение которой не меняется, у пользователя создается впечатление, что он взаимодействует с системой, обладающей изменяющимся состоянием. Один из способов разрешить парадокс заключается в том, чтобы понять, что именно существование пользователя во времени навязывает системе состояние. Если бы пользователь мог принять более отстраненную точку зрения и думать в терминах потоков и балансов, а не отдельных актов взаимодействия, система выглядела бы как объект без состояния.73

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

Моделирование при помощи объектов - мощная и интуитивно понятная техника, во многом потому, что она соответствует восприятию взаимодействия с миром, частью которого мы являемся. Однако, как мы неоднократно видели в этой главе, в таких моделях возникают неудобные вопросы управления порядком событий и синхронизации множественных процессов. Возможность избежать этих проблем стимулировала развитие функциональных языков программирования (functional programming languages), в которых нет понятий присваивания и изменяемых данных. В таком языке все процедуры реализуют точно определенные математические функции, поведение которых не меняется. Функциональный подход весьма привлекателен при работе с параллельными

74

системами.74

С другой стороны, при более внимательном взгляде мы обнаружим, что

73Подобным образом в физике, когда мы наблюдаем за движением частицы, мы говорим, что позиция (состояние) частицы изменяется. Однако с точки зрения мировой линии частицы в пространстве-времени никакого изменения нет.

74Джон Бэкус, изобретатель Фортрана, привлек внимание к функциональному программированию, когда в 1978 году получил премию Тьюринга Американской Ассоциации по Вычислительным Машинам (ACM). В своей инаугурационной речи (Backus 1978) он горячо отстаивал функциональный подход. Хороший обзор функционального программирования дается в книгах Henderson 1980 и Darlington, Henderson, and Turner 1982.


и функциональные модели не избавляют от проблем, связанных со временем. Одна из самых болезненных возникает, когда нам нужно проектировать интерактивные системы, особенно такие, которые моделируют взаимодействие между независимыми сущностями. К примеру, рассмотрим еще раз реализацию банковской системы, которая позволяет иметь совместные счета. В традиционной системе с присваиванием и объектами информация о том, что у Петра и Павла есть общий счет, моделировалась бы тем, что и Петр, и Павел посылали бы заказы на транзакции одному и тому же объекту-банковскому счету, как мы видели в разделе 3.1.3. С точки зрения потоков, где «объекты» сами по себе не существуют, банковский счет, как мы уже указывали, может моделироваться в виде процесса, работающего с потоком заказов на транзакции и порождающего поток реакций. Соответственно, информация о том, что Петр и Павел совместно владеют счетом, может моделироваться путем смешения потока заказов Петра на транзакции с потоком Павла и направления слитого потока в процесс-поток банковского счета, как показано на рисунке 3.38.

Проблему в этой формулировке вызывает понятие слияния (merge). Неверным решением будет просто брать по очереди один заказ от Петра и один от Павла. Допустим, что Павел очень редко обращается к счету. Не следует заставлять Петра ждать, пока Павел обратится к счету, прежде чем он сможет осуществить вторую транзакцию. Как бы ни было реализовано слияние, оно должно чередовать потоки транзакций так, чтобы соответствовать «реальному времени» с точки зрения Петра и Павла, в том смысле, что если Петр и Павел встретятся, то они могут согласиться, что определенные транзакции произошли до встречи, а определенные после.75 Это в точности то же самое ограничение, с которым нам приходилось сталкиваться в разделе 3.4.1, где у нас возникла необходимость ввести явную синхронизацию, чтобы добиться «правильного» порядка событий при параллельной обработке объектов, обладающих состоянием. Таким образом, при попытке поддержать функциональный стиль необходимость сливать потоки ввода от различных агентов опять привносит те самые проблемы, от которых функциональный стиль должен был нас избавить.

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

75Заметим, что для любых двух потоков в принципе существует более одного возможного способа чередования. Так что с технической точки зрения «слияние» не функция, а отношение - ответ не является детерминистской функцией аргументов. Мы уже упоминали (в примечании 39), что недетерминизм имеет существенное значение при работе с параллельными процессами. Отношение слияния показывает тот же самый недетерминизм с функциональной точки зрения. В разделе 4.3 мы рассмотрим еще одну точку зрения на недетерминизм.

76Объектная модель строит приближенное описание мира, разделяя его на отдельные фрагменты. Функциональная модель не проводит границ модулей по границам объектов. Объектная модель полезна тогда, когда раздельное состояние «объектов» намного больше, чем состояние, общее для всех или некоторых из них. Примером области, где объектный взгляд не работает, является квантовая механика, где попытки думать об объектах как отдельных частицах ведут к парадоксам и недоразумениям. Объединение объектного взгляда с функциональным может иметь отношение не столько к программированию, сколько к фундаментальным вопросам эпистемологии.



[стр.Начало] [стр.1] [стр.2] [стр.3] [стр.4] [стр.5] [стр.6] [стр.7] [стр.8] [стр.9] [стр.10] [стр.11] [стр.12] [стр.13] [стр.14] [стр.15] [стр.16] [стр.17] [стр.18] [стр.19] [стр.20] [стр.21] [стр.22] [стр.23] [стр.24] [стр.25] [стр.26] [стр.27] [стр.28] [стр.29] [стр.30] [стр.31] [стр.32] [стр.33] [стр.34] [стр.35] [стр.36] [стр.37] [стр.38] [стр.39] [стр.40] [стр.41] [стр.42] [стр.43] [стр.44] [стр.45] [стр.46] [стр.47] [стр.48] [стр.49] [стр.50] [стр.51] [стр.52] [стр.53] [стр.54] [стр.55] [стр.56] [стр.57] [стр.58] [стр.59] [стр.60] [стр.61] [стр.62] [стр.63] [стр.64] [стр.65] [стр.66] [стр.67] [стр.68] [стр.69] [стр.70] [стр.71] [стр.72] [стр.73] [стр.74] [стр.75] [стр.76] [стр.77] [стр.78] [стр.79] [стр.80] [стр.81] [стр.82] [стр.83] [стр.84] [стр.85] [стр.86] [стр.87] [стр.88] [стр.89] [стр.90] [стр.91] [стр.92] [стр.93] [стр.94] [стр.95] [стр.96] [стр.97] [стр.98] [стр.99] [стр.100] [стр.101] [стр.102] [стр.103] [стр.104] [стр.105] [стр.106] [стр.107] [стр.108] [стр.109] [стр.110] [стр.111] [стр.112] [стр.113] [стр.114] [стр.115] [стр.116] [стр.117] [стр.118] [стр.119] [стр.120] [стр.121] [стр.122] [стр.123] [стр.124] [стр.125] [стр.126] [стр.127] [стр.128] [стр.129] [стр.130] [стр.131] [стр.132] [стр.133] [стр.134] [стр.135] [стр.136] [стр.137] [стр.138] [стр.139] [стр.140] [стр.141] [стр.142] [стр.143] [стр.144] [стр.145] [стр.146] [стр.147] [стр.148] [стр.149] [стр.150] [стр.151] [стр.152] [стр.153] [стр.154] [стр.155] [стр.156] [стр.157] [стр.158] [стр.159] [стр.160] [стр.161] [стр.162] [стр.163] [стр.164] [стр.165] [стр.166] [стр.167] [стр.168] [стр.169] [стр.170] [стр.171] [стр.172] [стр.173] [стр.174] [стр.175] [стр.176] [стр.177] [стр.178] [стр.179] [стр.180] [стр.181] [стр.182] [стр.183] [стр.184] [стр.185] [стр.186] [стр.187] [стр.188] [стр.189] [стр.190] [стр.191] [стр.192] [стр.193] [стр.194] [стр.195] [стр.196]