Futures and promises

Поделись знанием:
Перейти к: навигация, поиск

В информатике конструкции future, promise и delay в некоторых языках программирования формируют стратегию вычисления, применяемую для параллельных вычислений. С их помощью описывается объект, к которому можно обратиться за результатом, вычисление которого может быть не завершено на данный момент.





Терминология

Термин promise был предложен в 1976 году Дэниэлом Фридманом и Дэвидом Вайзом,[1] а Питер Хиббард назвал его eventual.[2] Похожая концепция под названием future была предложена в 1977 году в статье Генри Бейкера и Карла Хьюитта.[3]

Термины future, promise и delay довольно часто взаимозаменяемы, однако далее описана разница между future и promise. Под future обычно имеется в виду представление переменной, доступное только для чтения, а под promise — изменяемый контейнер с одиночным присваиванием, который передаёт значение future.[4] Future может быть определён без указания того, из какого promise будет получено значение. Также с одним future может быть связано несколько promise, однако присвоить значение future сможет только один promise. В остальных случаях future и promise создаются вместе и привязываются друг к другу: future — это значение, а promise — это функция, которая присваивает значение. На практике future — возвращаемое значение асинхронной функции promise. Процесс присваивания значения future называют resolving, fulfilling или binding.

В некоторых источниках на русском используются следующие переводы терминов: для future — будущие результаты[5], фьючерс[6][7][8]; для promise — обещание[9][5]; для delay — задержка.

Следует отметить, что неисчислимый («будущее») и двусловный («будущее значение») варианты перевода имеют очень ограниченную применимость (см. обсуждение). В частности, язык Alice ML наделяет futures первоклассными свойствами, в том числе, предоставляя первоклассные futures уровня ML-модулейfuture modules и future type modules[10] — и все эти термины оказываются непереводимы с использованием этих вариантов. Возможным вариантом перевода термина в этом случае оказывается «будущность» — соответственно, давая группу терминов «первоклассные будущности», «будущности уровня модулей», «будущные структуры» и «будущные сигнатуры». Возможен вольный перевод «перспектива», с соответствующим терминологическим рядом.

Неявное и явное использование future

Использование future может быть неявным (при любом обращении к future возвращается ссылка на значение) и явным (пользователь должен вызвать функцию, чтобы получить значение). Примером может служить метод get класса [java.sun.com/javase/6/docs/api/java/util/concurrent/Future.html java.util.concurrent.Future] в языке Java. Получение значения из явного future называют stinging или forcing. Явные future могут быть реализованы в качестве библиотеки, в то время, как неявные обычно реализуются как часть языка.

В статье Бейкера и Хьюитта описаны неявные future, которые естественным образом поддерживаются в вычислительной модели акторов и чисто объектно-ориентированных языках, таких как Smalltalk. В статье Фридмана и Вайза описаны только явные future, скорее всего из-за сложности реализации неявных future на обычных компьютерах. Сложность заключается в том, что на аппаратном уровне не получится работать с future как с примитивным типом данных вроде целых чисел. Например, при помощи инструкции добавления не получится обработать 3 + future factorial(100000). В чисто объектных языках и языках, поддерживающих модель акторов, данная проблема может быть решена отправкой future factorial(100000) сообщения +[3], в котором future будет сообщено, что нужно добавить 3 и вернуть результат. Стоит заметить, что подход с передачей сообщения работает вне зависимости от того, сколько времени уйдёт на вычисление factorial(100000), при этом не требуется применять stinging или forcing.

Конвейер из promise

При использовании future значительно сокращаются задержки в распределённых системах. К примеру, при помощи future можно создать конвейер из promise[11][12], который реализован в таких языках, как E и Joule, а также в Argus под названием call-stream.

Рассмотрим выражение, использующее традиционные удалённые вызовы процедур:

 t3 := ( x.a() ).c( y.b() )

которое можно раскрыть как

 t1 := x.a();
 t2 := y.b();
 t3 := t1.c(t2);

В каждом утверждении нужно сначала послать сообщение и получить на него ответ прежде, чем приступить к выполнению следующего. Предположим, что x, y, t1 и t2 находятся на одной и той же удалённой машине. В таком случае для выполнения третьего утверждения сначала потребуется выполнить две пересылки данных по сети. Затем третье утверждение выполнит ещё одну пересылку данных на ту же удалённую машину.

Данное выражение может быть переписано с использованием future

 t3 := (x <- a()) <- c(y <- b())

и раскрыто как

 t1 := x <- a();
 t2 := y <- b();
 t3 := t1 <- c(t2);

Здесь используется синтаксис из языка E, где x <- a() означает «асинхронно переслать сообщение a() в x». Все три переменные становятся future, и выполнение программы продолжается. Позже, при попытке получить значение t3, может возникнуть задержка; однако, использование конвейера может её уменьшить. Если, как и в предыдущем примере, x, y, t1 и t2 расположены на одной удалённой машине, то можно реализовать вычисление t3 с применением конвейера и одной пересылкой данных по сети. Так как все три сообщения предназначены для переменных, находящихся на одной удалённой машине, то для получения результата нужно выполнить всего один запрос и получить один ответ. Стоит заметить, что передача t1 <- c(t2) не будет заблокирована, даже если t1 и t2 были на разных машинах по отношению друг к другу или к x и y.

Использование конвейера из promise следует отличать от параллельной асинхронной передачи сообщения. В системах, поддерживающих параллельную передачу сообщений, но не поддерживающих конвейеры, отправка сообщений x <- a() и y <- b() из примера может быть выполнена параллельно, но для передачи t1 <- c(t2) нужно будет дождаться получения t1 и t2, даже если x, y, t1 и t2 находятся на одной и той же удалённой машине. Преимущество во времени задержки при использовании конвейера становится более весомым в сложных ситуациях, где требуется пересылка множества сообщений.

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

Неизменяемые представления

В некоторых языках программирования, таких как Oz, E и AmbientTalk, возможно получить неизменяемое представление future, которое позволяет получить его значение после resolve, но не позволяет сделать resolve:

  • В Oz для получения неизменяемого представления используется оператор !!.
  • В E и AmbientTalk future представляет собой пару значений promise/resolver. Promise представляет собой неизменяемое представление, а resolver необходим для присваивания значения future.
  • В C++11 std::future представляет собой неизменяемое представление. Значение присваивается напрямую при помощи std::promise или получается из результата выполнения функции std::packaged_task или std::async.
  • В Dojo Toolkit Deferred API 1.5 consumer-only promise object представляет собой неизменяемое представление.[13]
  • В Alice ML future предоставляют только неизменяемое представление, а promise содержит возможности future и способность сделать resolve[14][15]
  • В .NET 4.0 System.Threading.Tasks.Task<T> представляет собой неизменяемое представление. Resolve значения может быть выполнен при помощи System.Threading.Tasks.TaskCompletionSource<T>.

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

Future, привязанные к потокам

В некоторых языках, таких как Alice ML, future привязываются к определенному потоку, который вычисляет значение. Вычисление может начаться сразу при создании future или лениво, то есть при первой необходимости. «Ленивый» future напоминает thunk (в плане отложенного вычисления).

Alice ML также поддерживает future, которые могут быть разрешены любым потоком, и там это тоже называется promise.[14] Стоит заметить, что в данном контексте promise означает не то, что в примере на языке E, рассмотренном выше: promise в Alice не является неизменяемым представлением, и в Alice не поддерживается создание конвейеров из promise. Зато конвейеры естественным образом работают с future (включая те, которые привязаны к promise).

Блокирующая и неблокирующая семантика

Если выполняется асинхронный доступ к значению future, например, при передаче ему сообщения или ожидании с использованием конструкции when в E, то не составляет труда дождаться разрешения future перед получением сообщения. Это единственный момент, который нужно учитывать в чисто асинхронных системах, таких как языки с моделью акторов.

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

  • при получении доступа текущий поток или процесс блокируется до тех пока, пока не разрешится future (возможно, с применением ожидания). Это семантика потоковых переменных в языке Oz.
  • попытка синхронно получить доступ всегда выдаёт ошибку, например, выбрасывание исключения. Это семантика удалённых promise в E.[16]
  • теоретически возможна такая ситуация, что доступ будет получен, если future разрешён, а иначе будет вызвана ошибка. Такой подход не является хорошим, так как программа становится недетерминированной, и возникает потенциальное состояние гонки.

Первый способ, к примеру, реализован в C++11, где поток, в котором требуется получить значение future, может заблокироваться до тех пор, пока не будут вызваны функции-члены wait() или get(). Используя wait_for() или wait_until(), можно явно указать время ожидания, чтобы избежать вечной блокировки. Если future получается в результате выполнения std::async, тогда при блокирующем ожидании (без таймаута) на ожидающем потоке может быть синхронно получен результат выполнения функции.

Похожие конструкции

I-переменная (в языке Id) представляет собой future с блокирующей семантикой, описанной выше. I-структура — структура данных, состоящая из I-переменных. Похожая конструкция, используемая для синхронизации, в которой значение можно присвоить несколько раз, называется M-переменной. M-переменные поддерживают атомные операции получения и записи значения переменной, где получение значения возвращает M-переменную в пустое состояние.[17]

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

Параллельная переменная с ограничениями является обобщением параллельных логических переменных с поддержкой логического программирования с ограничениями: ограничение может несколько раз сужать набор допустимых значений. Обычно существует способ указания thunk, который будет выполняться при каждом сужении; это необходимо для поддержки распространения ограничения.

Выразительность различных форм future

Энергично вычисляемые потоко-специфичные future могут быть реализованы непосредственно в терминах не потоко-специфичных future, путём создания потока для вычисления значения в момент создания future. В этом случае желательно возвращать клиенту представление с доступом только на чтение, так что только созданный поток сможет исполнить данный future.

Для реализации неявных ленивых потоко-специфичных futures (например, как в языке Alice ML) в терминах не потоко-специфичных future требуется механизм определения первой точки использования значения future (например, конструкция WaitNeeded в Oz[18]). Если все значения являются объектами, то достаточно возможности реализовать прозрачные объекты для пересылки значения, поскольку первое же сообщение к пересылающему объекту обозначит необходимость вычисления значения future.

Не потоко-специфичные future могут быть реализованы через потоко-специфичные future в предположении, что система поддерживает передачу сообщений. Поток, требующий значение future может послать сообщение потоку future. Однако, этот подход вносит избыточную сложность. В языках программирования, основанных на потоках, наиболее выразительным подходом вероятно является комбинация не потоко-специфичных future, представлений с доступом только по чтению и либо конструкция 'WaitNeeded', либо поддержка прозрачной пересылки.

Стратегия вычисления

Стратегия вычисления «вызов по преднамеченности» (англ. call by future) является недетерминированной: значение future будет вычислено в какой-то момент времени после создания, но перед использованием. Вычисление может быть начато непосредственно после создания future («энергичные вычисления» — eager evaluation), или лишь в момент, когда потребуется значение (ленивые вычисления, отложенные вычисления). После того, как результат future вычислен, при последующих обращениях не происходит повторного вычисления. Таким образом future сходны с Вызовом-по-необходимости (мемоизация, call by need).

Концепция lazy future ("ленивый" future) предоставляет детерминированную семантику ленивого вычисления: вычисление значения future начинается при первом использовании значения, как в методе "call by need". Lazy future полезны в языках программирования, не предоставляющих ленивых вычислений. Например, в C++11 подобная конструкция может быть создана указанием политики запуска std::launch::sync для std::async с передачей функции, вычисляющей значение.

Семантика future в модели акторов

В модели Акторов, выражение в виде ''future'' <Expression> определяется реакцией на сообщение Eval в окружении E для потребителя C таким образом: Выражение future отвечает на сообщение Eval отправкой потребителю C нового созданного актора F (прокси для ответа с вычислением <Expression>) в качестве возвращаемого значения, одновременно с отправкой выражению <Expression> сообщения Eval в окружении E для потребителя C. Поведение F определено так:

  • Когда F получает запрос R, он проверяет, был ли ранее получен ответ (возвращаемое значение или исключение) от вычисления <Expression>:
    1. Если был получен ответ V, тогда
      • Если V является значением, послать его в ответ на запрос R.
      • Если V является исключением, послать его отправителю запроса R.
    2. Если ответ не был ранее получен, R сохраняется в очереди запросов внутри F.
  • Когда F получает ответ V от вычисления <Expression>, данный ответ сохраняется в F и
    • Если V является значением, все запросы из очереди получают V.
    • Если V является исключением, оно пересылается всем отправителям запросов, хранящимся в очереди.

Некоторые реализации future могут иначе обрабатывать запросы для увеличения степени параллелизма. Например, выражение 1 + future factorial(n) может создать новый future, который будет вести себя как число 1+factorial(n).

История

Конструкции future и promise впервые были реализованы в языках программирования MultiLisp и Act 1. Использование логических переменных для взаимодействия в конкурентных языках логического программирования достаточно сходно с future. Среди них можно назвать Prolog with Freeze и IC Prolog, полноценный конкурентный примитив был реализован Relational Language, Concurrent Prolog, Guarded Horn Clauses (GHC), Parlog, Strand, Vulcan, Janus, Mozart/Oz, Flow Java и Alice ML. Однократные присваивания I-var из языков программирования потоков данных (dataflow), изначально появившиеся в Id и включенные в Reppy Concurrent ML, схожи с конкурентными логическими переменными.

Техника конвейера из promise, использующая futures для преодоления задержек, была предложена Барбарой Лисков и Liuba Shrira в 1988 году[19], и, независимо от них, Mark S. Miller, Dean Tribble и Rob Jellinghaus в рамках Project Xanadu около 1989[20].

Термин promise был предложен Лисков и Shrira, хотя они назвали механизм конвейеризации call-stream (сейчас это название используется редко).

В обоих работах и в реализации конвейера promise в Xanadu, значения promise не являлись объектом первого класса: аргументы функций и возвращаемые значения не могли являться непосредственно promise (что усложняет реализацию конвейера, например в Xanadu). promise и call-stream не были реализованы в публичных версиях Argus[21] (языка программирования, использованных в работах Лисков и Shrira); Argus прекратил развитие в 1988 году.[22] Реализация конвейера в Xanadu стала доступна только с выходом Udanax Gold[23] в 1999, и не объяснялась в опубликованной документации.[24]

Реализации promise в Joule и E поддерживают их в качестве объектов первого класса.

Несколько ранних Actor-языков, в том числе языки Act,[25][26] поддерживали параллельную передачу сообщений и конвейерную обработку сообщений, но не конвейер promise. (Несмотря на возможность реализации конвейера promise через поддерживаемые конструкции, нет свидетельств подобных реализаций в языках Act.)

Каналы

Концепция Future может быть реализована в терминах каналов: future является одноэлементным каналом, а promise является процессом, посылающим значение в канал, выполняя future[27]. Таким образом реализуются future в таких конкурентных языках с поддержкой каналов как CSP и Go. Реализуемые в них future являются явными, поскольку доступ к ним производится через чтение из канала, а не в рамках обычного вычисления выражений.

Напишите отзыв о статье "Futures and promises"

Примечания

  1. Friedman, Daniel (1976). "The Impact of Applicative Programming on Multiprocessing". International Conference on Parallel Processing, pp. 263-272.. 
  2. Hibbard, Peter (1976). "Parallel Processing Facilities". New Directions in Algorithmic Languages, (ed.) Stephen A. Schuman, IRIA, 1976.. 
  3. Henry Baker and Carl Hewitt (August 1977). "The Incremental Garbage Collection of Processes". Proceedings of the Symposium on Artificial Intelligence Programming Languages, SIGPLAN Notices 12. 
  4. [docs.scala-lang.org/sips/completed/futures-promises.html SIP-14 — Futures and Promises] // Scala
  5. 1 2 Энтони Уильямс. [books.google.com/books?id=1UXRAAAAQBAJ Параллельное программирование на C++ в действии. Практика разработки многопоточных программ]. — 2014-10-24. — 674 с. — ISBN 9785457427020.
  6. edu.mmcs.sfedu.ru/mod/resource/view.php?id=6320
  7. Словарь LingvoComputer (En-Ru) futures - фьючерс
  8. [msdn.microsoft.com/ru-ru/library/dd764564.aspx Пошаговое руководство. Реализация фьючерсов]. msdn.microsoft.com. Проверено 10 сентября 2016.
  9. download2.nust.na/pub4/sourceforge/c/cp/cpp-lects-rus/cpp_lectures.pdf
  10. Andreas Rossberg. [www.mpi-sws.org/~rossberg/papers/thesis.pdf Typed Open Programming] // Dissertation. — Universitat des Saarlandes, 2007.
  11. [www.erights.org/elib/distrib/pipeline.html Promise Pipelining at erights.org], язык E
  12. [c2.com/cgi/wiki?PromisePipelining Promise Pipelining] // C2 wiki, 2010
  13. [www.sitepen.com/blog/2010/05/03/robust-promises-with-dojo-deferred-1-5/ Robust promises with Dojo deferred], Site Pen, 2010-05-03, <www.sitepen.com/blog/2010/05/03/robust-promises-with-dojo-deferred-1-5/> .
  14. 1 2 [www.ps.uni-sb.de/alice/manual/library/promise.html "Promise"], Alice Manual, DE: Uni-SB, <www.ps.uni-sb.de/alice/manual/library/promise.html> .
  15. [www.ps.uni-sb.de/alice/manual/library/future.html "Future"], Alice manual, DE: Uni-SB, <www.ps.uni-sb.de/alice/manual/library/future.html> .
  16. [wiki.erights.org/wiki/Promise Promise], E rights, <wiki.erights.org/wiki/Promise> .
  17. [www.haskell.org/ghc/docs/latest/html/libraries/base/Control-Concurrent-MVar.html Control Concurrent MVar], Haskell, <www.haskell.org/ghc/docs/latest/html/libraries/base/Control-Concurrent-MVar.html> .
  18. [www.mozart-oz.org/home/doc/base/node13.html WaitNeeded], Mozart Oz, <www.mozart-oz.org/home/doc/base/node13.html> .
  19. Barbara Liskov and Liuba Shrira (1988). «Promises: Linguistic Support for Efficient Asynchronous Procedure Calls in Distributed Systems» (Proceedings of the SIGPLAN '88 Conference on Programming Language Design and Implementation; Atlanta, Georgia, United States, pp. 260–267. ISBN 0-89791-269-1, published by ACM. Also published in ACM SIGPLAN Notices, Volume 23, Issue 7, July 1988). DOI:10.1145/53990.54016.
  20. [www.sunless-sea.net/Transcripts/promise.html Promise], Sunless Sea, <www.sunless-sea.net/Transcripts/promise.html> .
  21. [www.pmg.csail.mit.edu/Argus.html Argus], MIT, <www.pmg.csail.mit.edu/Argus.html> .
  22. Liskov, Barbara, [www.ieeeghn.org/wiki/index.php/Oral-History:Barbara_Liskov#Distributed_Computing_and_Argus Distributed computing and Argus], Oral history, IEEE GHN, <www.ieeeghn.org/wiki/index.php/Oral-History:Barbara_Liskov#Distributed_Computing_and_Argus> .
  23. [www.udanax.com/gold/ Gold], Udanax, <www.udanax.com/gold/> .
  24. [www.erights.org/elib/distrib/pipeline.html Pipeline], E rights, <www.erights.org/elib/distrib/pipeline.html> .
  25. Henry Lieberman (June 1981). «A Preview of Act 1» (MIT AI memo 625).
  26. Henry Lieberman (June 1981). «Thinking About Lots of Things at Once without Getting Confused: Parallelism in Act 1» (MIT AI memo 626).
  27. «[sites.google.com/site/gopatterns/concurrency/futures Futures]», [sites.google.com/site/gopatterns Go Language Patterns]

Ссылки

  • [c2.com/cgi/wiki?FutureValue Future Value] и [c2.com/cgi/wiki?PromisePipelining Promise Pipelining] в энциклопедии C2 (Portland Pattern Repository)  (англ.)
  • [aspn.activestate.com/ASPN/Cookbook/Python/Recipe/84317 Easy Threading with Futures] в языке программирования Python  (англ.)
  • scrutator.me/post/2012/06/03/parallel-world-p2.aspx

Отрывок, характеризующий Futures and promises

– К нам милости просим, у наших господ всего много, пожалуйте, – говорила Мавра Кузминишна. – А что, очень нездоровы? – прибавила она.
Камердинер махнул рукой.
– Не чаем довезти! У доктора спросить надо. – И камердинер сошел с козел и подошел к повозке.
– Хорошо, – сказал доктор.
Камердинер подошел опять к коляске, заглянул в нее, покачал головой, велел кучеру заворачивать на двор и остановился подле Мавры Кузминишны.
– Господи Иисусе Христе! – проговорила она.
Мавра Кузминишна предлагала внести раненого в дом.
– Господа ничего не скажут… – говорила она. Но надо было избежать подъема на лестницу, и потому раненого внесли во флигель и положили в бывшей комнате m me Schoss. Раненый этот был князь Андрей Болконский.


Наступил последний день Москвы. Была ясная веселая осенняя погода. Было воскресенье. Как и в обыкновенные воскресенья, благовестили к обедне во всех церквах. Никто, казалось, еще не мог понять того, что ожидает Москву.
Только два указателя состояния общества выражали то положение, в котором была Москва: чернь, то есть сословие бедных людей, и цены на предметы. Фабричные, дворовые и мужики огромной толпой, в которую замешались чиновники, семинаристы, дворяне, в этот день рано утром вышли на Три Горы. Постояв там и не дождавшись Растопчина и убедившись в том, что Москва будет сдана, эта толпа рассыпалась по Москве, по питейным домам и трактирам. Цены в этот день тоже указывали на положение дел. Цены на оружие, на золото, на телеги и лошадей всё шли возвышаясь, а цены на бумажки и на городские вещи всё шли уменьшаясь, так что в середине дня были случаи, что дорогие товары, как сукна, извозчики вывозили исполу, а за мужицкую лошадь платили пятьсот рублей; мебель же, зеркала, бронзы отдавали даром.
В степенном и старом доме Ростовых распадение прежних условий жизни выразилось очень слабо. В отношении людей было только то, что в ночь пропало три человека из огромной дворни; но ничего не было украдено; и в отношении цен вещей оказалось то, что тридцать подвод, пришедшие из деревень, были огромное богатство, которому многие завидовали и за которые Ростовым предлагали огромные деньги. Мало того, что за эти подводы предлагали огромные деньги, с вечера и рано утром 1 го сентября на двор к Ростовым приходили посланные денщики и слуги от раненых офицеров и притаскивались сами раненые, помещенные у Ростовых и в соседних домах, и умоляли людей Ростовых похлопотать о том, чтоб им дали подводы для выезда из Москвы. Дворецкий, к которому обращались с такими просьбами, хотя и жалел раненых, решительно отказывал, говоря, что он даже и не посмеет доложить о том графу. Как ни жалки были остающиеся раненые, было очевидно, что, отдай одну подводу, не было причины не отдать другую, все – отдать и свои экипажи. Тридцать подвод не могли спасти всех раненых, а в общем бедствии нельзя было не думать о себе и своей семье. Так думал дворецкий за своего барина.
Проснувшись утром 1 го числа, граф Илья Андреич потихоньку вышел из спальни, чтобы не разбудить к утру только заснувшую графиню, и в своем лиловом шелковом халате вышел на крыльцо. Подводы, увязанные, стояли на дворе. У крыльца стояли экипажи. Дворецкий стоял у подъезда, разговаривая с стариком денщиком и молодым, бледным офицером с подвязанной рукой. Дворецкий, увидав графа, сделал офицеру и денщику значительный и строгий знак, чтобы они удалились.
– Ну, что, все готово, Васильич? – сказал граф, потирая свою лысину и добродушно глядя на офицера и денщика и кивая им головой. (Граф любил новые лица.)
– Хоть сейчас запрягать, ваше сиятельство.
– Ну и славно, вот графиня проснется, и с богом! Вы что, господа? – обратился он к офицеру. – У меня в доме? – Офицер придвинулся ближе. Бледное лицо его вспыхнуло вдруг яркой краской.
– Граф, сделайте одолжение, позвольте мне… ради бога… где нибудь приютиться на ваших подводах. Здесь у меня ничего с собой нет… Мне на возу… все равно… – Еще не успел договорить офицер, как денщик с той же просьбой для своего господина обратился к графу.
– А! да, да, да, – поспешно заговорил граф. – Я очень, очень рад. Васильич, ты распорядись, ну там очистить одну или две телеги, ну там… что же… что нужно… – какими то неопределенными выражениями, что то приказывая, сказал граф. Но в то же мгновение горячее выражение благодарности офицера уже закрепило то, что он приказывал. Граф оглянулся вокруг себя: на дворе, в воротах, в окне флигеля виднелись раненые и денщики. Все они смотрели на графа и подвигались к крыльцу.
– Пожалуйте, ваше сиятельство, в галерею: там как прикажете насчет картин? – сказал дворецкий. И граф вместе с ним вошел в дом, повторяя свое приказание о том, чтобы не отказывать раненым, которые просятся ехать.
– Ну, что же, можно сложить что нибудь, – прибавил он тихим, таинственным голосом, как будто боясь, чтобы кто нибудь его не услышал.
В девять часов проснулась графиня, и Матрена Тимофеевна, бывшая ее горничная, исполнявшая в отношении графини должность шефа жандармов, пришла доложить своей бывшей барышне, что Марья Карловна очень обижены и что барышниным летним платьям нельзя остаться здесь. На расспросы графини, почему m me Schoss обижена, открылось, что ее сундук сняли с подводы и все подводы развязывают – добро снимают и набирают с собой раненых, которых граф, по своей простоте, приказал забирать с собой. Графиня велела попросить к себе мужа.
– Что это, мой друг, я слышу, вещи опять снимают?
– Знаешь, ma chere, я вот что хотел тебе сказать… ma chere графинюшка… ко мне приходил офицер, просят, чтобы дать несколько подвод под раненых. Ведь это все дело наживное; а каково им оставаться, подумай!.. Право, у нас на дворе, сами мы их зазвали, офицеры тут есть. Знаешь, думаю, право, ma chere, вот, ma chere… пускай их свезут… куда же торопиться?.. – Граф робко сказал это, как он всегда говорил, когда дело шло о деньгах. Графиня же привыкла уж к этому тону, всегда предшествовавшему делу, разорявшему детей, как какая нибудь постройка галереи, оранжереи, устройство домашнего театра или музыки, – и привыкла, и долгом считала всегда противоборствовать тому, что выражалось этим робким тоном.
Она приняла свой покорно плачевный вид и сказала мужу:
– Послушай, граф, ты довел до того, что за дом ничего не дают, а теперь и все наше – детское состояние погубить хочешь. Ведь ты сам говоришь, что в доме на сто тысяч добра. Я, мой друг, не согласна и не согласна. Воля твоя! На раненых есть правительство. Они знают. Посмотри: вон напротив, у Лопухиных, еще третьего дня все дочиста вывезли. Вот как люди делают. Одни мы дураки. Пожалей хоть не меня, так детей.
Граф замахал руками и, ничего не сказав, вышел из комнаты.
– Папа! об чем вы это? – сказала ему Наташа, вслед за ним вошедшая в комнату матери.
– Ни о чем! Тебе что за дело! – сердито проговорил граф.
– Нет, я слышала, – сказала Наташа. – Отчего ж маменька не хочет?
– Тебе что за дело? – крикнул граф. Наташа отошла к окну и задумалась.
– Папенька, Берг к нам приехал, – сказала она, глядя в окно.


Берг, зять Ростовых, был уже полковник с Владимиром и Анной на шее и занимал все то же покойное и приятное место помощника начальника штаба, помощника первого отделения начальника штаба второго корпуса.
Он 1 сентября приехал из армии в Москву.
Ему в Москве нечего было делать; но он заметил, что все из армии просились в Москву и что то там делали. Он счел тоже нужным отпроситься для домашних и семейных дел.
Берг, в своих аккуратных дрожечках на паре сытых саврасеньких, точно таких, какие были у одного князя, подъехал к дому своего тестя. Он внимательно посмотрел во двор на подводы и, входя на крыльцо, вынул чистый носовой платок и завязал узел.
Из передней Берг плывущим, нетерпеливым шагом вбежал в гостиную и обнял графа, поцеловал ручки у Наташи и Сони и поспешно спросил о здоровье мамаши.
– Какое теперь здоровье? Ну, рассказывай же, – сказал граф, – что войска? Отступают или будет еще сраженье?
– Один предвечный бог, папаша, – сказал Берг, – может решить судьбы отечества. Армия горит духом геройства, и теперь вожди, так сказать, собрались на совещание. Что будет, неизвестно. Но я вам скажу вообще, папаша, такого геройского духа, истинно древнего мужества российских войск, которое они – оно, – поправился он, – показали или выказали в этой битве 26 числа, нет никаких слов достойных, чтоб их описать… Я вам скажу, папаша (он ударил себя в грудь так же, как ударял себя один рассказывавший при нем генерал, хотя несколько поздно, потому что ударить себя в грудь надо было при слове «российское войско»), – я вам скажу откровенно, что мы, начальники, не только не должны были подгонять солдат или что нибудь такое, но мы насилу могли удерживать эти, эти… да, мужественные и древние подвиги, – сказал он скороговоркой. – Генерал Барклай до Толли жертвовал жизнью своей везде впереди войска, я вам скажу. Наш же корпус был поставлен на скате горы. Можете себе представить! – И тут Берг рассказал все, что он запомнил, из разных слышанных за это время рассказов. Наташа, не спуская взгляда, который смущал Берга, как будто отыскивая на его лице решения какого то вопроса, смотрела на него.
– Такое геройство вообще, каковое выказали российские воины, нельзя представить и достойно восхвалить! – сказал Берг, оглядываясь на Наташу и как бы желая ее задобрить, улыбаясь ей в ответ на ее упорный взгляд… – «Россия не в Москве, она в сердцах се сынов!» Так, папаша? – сказал Берг.
В это время из диванной, с усталым и недовольным видом, вышла графиня. Берг поспешно вскочил, поцеловал ручку графини, осведомился о ее здоровье и, выражая свое сочувствие покачиваньем головы, остановился подле нее.
– Да, мамаша, я вам истинно скажу, тяжелые и грустные времена для всякого русского. Но зачем же так беспокоиться? Вы еще успеете уехать…
– Я не понимаю, что делают люди, – сказала графиня, обращаясь к мужу, – мне сейчас сказали, что еще ничего не готово. Ведь надо же кому нибудь распорядиться. Вот и пожалеешь о Митеньке. Это конца не будет?
Граф хотел что то сказать, но, видимо, воздержался. Он встал с своего стула и пошел к двери.
Берг в это время, как бы для того, чтобы высморкаться, достал платок и, глядя на узелок, задумался, грустно и значительно покачивая головой.
– А у меня к вам, папаша, большая просьба, – сказал он.
– Гм?.. – сказал граф, останавливаясь.
– Еду я сейчас мимо Юсупова дома, – смеясь, сказал Берг. – Управляющий мне знакомый, выбежал и просит, не купите ли что нибудь. Я зашел, знаете, из любопытства, и там одна шифоньерочка и туалет. Вы знаете, как Верушка этого желала и как мы спорили об этом. (Берг невольно перешел в тон радости о своей благоустроенности, когда он начал говорить про шифоньерку и туалет.) И такая прелесть! выдвигается и с аглицким секретом, знаете? А Верочке давно хотелось. Так мне хочется ей сюрприз сделать. Я видел у вас так много этих мужиков на дворе. Дайте мне одного, пожалуйста, я ему хорошенько заплачу и…
Граф сморщился и заперхал.
– У графини просите, а я не распоряжаюсь.
– Ежели затруднительно, пожалуйста, не надо, – сказал Берг. – Мне для Верушки только очень бы хотелось.
– Ах, убирайтесь вы все к черту, к черту, к черту и к черту!.. – закричал старый граф. – Голова кругом идет. – И он вышел из комнаты.
Графиня заплакала.
– Да, да, маменька, очень тяжелые времена! – сказал Берг.
Наташа вышла вместе с отцом и, как будто с трудом соображая что то, сначала пошла за ним, а потом побежала вниз.
На крыльце стоял Петя, занимавшийся вооружением людей, которые ехали из Москвы. На дворе все так же стояли заложенные подводы. Две из них были развязаны, и на одну из них влезал офицер, поддерживаемый денщиком.
– Ты знаешь за что? – спросил Петя Наташу (Наташа поняла, что Петя разумел: за что поссорились отец с матерью). Она не отвечала.
– За то, что папенька хотел отдать все подводы под ранепых, – сказал Петя. – Мне Васильич сказал. По моему…
– По моему, – вдруг закричала почти Наташа, обращая свое озлобленное лицо к Пете, – по моему, это такая гадость, такая мерзость, такая… я не знаю! Разве мы немцы какие нибудь?.. – Горло ее задрожало от судорожных рыданий, и она, боясь ослабеть и выпустить даром заряд своей злобы, повернулась и стремительно бросилась по лестнице. Берг сидел подле графини и родственно почтительно утешал ее. Граф с трубкой в руках ходил по комнате, когда Наташа, с изуродованным злобой лицом, как буря ворвалась в комнату и быстрыми шагами подошла к матери.
– Это гадость! Это мерзость! – закричала она. – Это не может быть, чтобы вы приказали.
Берг и графиня недоумевающе и испуганно смотрели на нее. Граф остановился у окна, прислушиваясь.
– Маменька, это нельзя; посмотрите, что на дворе! – закричала она. – Они остаются!..
– Что с тобой? Кто они? Что тебе надо?
– Раненые, вот кто! Это нельзя, маменька; это ни на что не похоже… Нет, маменька, голубушка, это не то, простите, пожалуйста, голубушка… Маменька, ну что нам то, что мы увезем, вы посмотрите только, что на дворе… Маменька!.. Это не может быть!..
Граф стоял у окна и, не поворачивая лица, слушал слова Наташи. Вдруг он засопел носом и приблизил свое лицо к окну.
Графиня взглянула на дочь, увидала ее пристыженное за мать лицо, увидала ее волнение, поняла, отчего муж теперь не оглядывался на нее, и с растерянным видом оглянулась вокруг себя.
– Ах, да делайте, как хотите! Разве я мешаю кому нибудь! – сказала она, еще не вдруг сдаваясь.
– Маменька, голубушка, простите меня!
Но графиня оттолкнула дочь и подошла к графу.
– Mon cher, ты распорядись, как надо… Я ведь не знаю этого, – сказала она, виновато опуская глаза.
– Яйца… яйца курицу учат… – сквозь счастливые слезы проговорил граф и обнял жену, которая рада была скрыть на его груди свое пристыженное лицо.
– Папенька, маменька! Можно распорядиться? Можно?.. – спрашивала Наташа. – Мы все таки возьмем все самое нужное… – говорила Наташа.
Граф утвердительно кивнул ей головой, и Наташа тем быстрым бегом, которым она бегивала в горелки, побежала по зале в переднюю и по лестнице на двор.
Люди собрались около Наташи и до тех пор не могли поверить тому странному приказанию, которое она передавала, пока сам граф именем своей жены не подтвердил приказания о том, чтобы отдавать все подводы под раненых, а сундуки сносить в кладовые. Поняв приказание, люди с радостью и хлопотливостью принялись за новое дело. Прислуге теперь это не только не казалось странным, но, напротив, казалось, что это не могло быть иначе, точно так же, как за четверть часа перед этим никому не только не казалось странным, что оставляют раненых, а берут вещи, но казалось, что не могло быть иначе.
Все домашние, как бы выплачивая за то, что они раньше не взялись за это, принялись с хлопотливостью за новое дело размещения раненых. Раненые повыползли из своих комнат и с радостными бледными лицами окружили подводы. В соседних домах тоже разнесся слух, что есть подводы, и на двор к Ростовым стали приходить раненые из других домов. Многие из раненых просили не снимать вещей и только посадить их сверху. Но раз начавшееся дело свалки вещей уже не могло остановиться. Было все равно, оставлять все или половину. На дворе лежали неубранные сундуки с посудой, с бронзой, с картинами, зеркалами, которые так старательно укладывали в прошлую ночь, и всё искали и находили возможность сложить то и то и отдать еще и еще подводы.
– Четверых еще можно взять, – говорил управляющий, – я свою повозку отдаю, а то куда же их?
– Да отдайте мою гардеробную, – говорила графиня. – Дуняша со мной сядет в карету.
Отдали еще и гардеробную повозку и отправили ее за ранеными через два дома. Все домашние и прислуга были весело оживлены. Наташа находилась в восторженно счастливом оживлении, которого она давно не испытывала.
– Куда же его привязать? – говорили люди, прилаживая сундук к узкой запятке кареты, – надо хоть одну подводу оставить.
– Да с чем он? – спрашивала Наташа.
– С книгами графскими.
– Оставьте. Васильич уберет. Это не нужно.
В бричке все было полно людей; сомневались о том, куда сядет Петр Ильич.
– Он на козлы. Ведь ты на козлы, Петя? – кричала Наташа.
Соня не переставая хлопотала тоже; но цель хлопот ее была противоположна цели Наташи. Она убирала те вещи, которые должны были остаться; записывала их, по желанию графини, и старалась захватить с собой как можно больше.


Во втором часу заложенные и уложенные четыре экипажа Ростовых стояли у подъезда. Подводы с ранеными одна за другой съезжали со двора.
Коляска, в которой везли князя Андрея, проезжая мимо крыльца, обратила на себя внимание Сони, устраивавшей вместе с девушкой сиденья для графини в ее огромной высокой карете, стоявшей у подъезда.
– Это чья же коляска? – спросила Соня, высунувшись в окно кареты.
– А вы разве не знали, барышня? – отвечала горничная. – Князь раненый: он у нас ночевал и тоже с нами едут.
– Да кто это? Как фамилия?
– Самый наш жених бывший, князь Болконский! – вздыхая, отвечала горничная. – Говорят, при смерти.
Соня выскочила из кареты и побежала к графине. Графиня, уже одетая по дорожному, в шали и шляпе, усталая, ходила по гостиной, ожидая домашних, с тем чтобы посидеть с закрытыми дверями и помолиться перед отъездом. Наташи не было в комнате.
– Maman, – сказала Соня, – князь Андрей здесь, раненый, при смерти. Он едет с нами.
Графиня испуганно открыла глаза и, схватив за руку Соню, оглянулась.
– Наташа? – проговорила она.
И для Сони и для графини известие это имело в первую минуту только одно значение. Они знали свою Наташу, и ужас о том, что будет с нею при этом известии, заглушал для них всякое сочувствие к человеку, которого они обе любили.
– Наташа не знает еще; но он едет с нами, – сказала Соня.
– Ты говоришь, при смерти?
Соня кивнула головой.
Графиня обняла Соню и заплакала.
«Пути господни неисповедимы!» – думала она, чувствуя, что во всем, что делалось теперь, начинала выступать скрывавшаяся прежде от взгляда людей всемогущая рука.
– Ну, мама, все готово. О чем вы?.. – спросила с оживленным лицом Наташа, вбегая в комнату.
– Ни о чем, – сказала графиня. – Готово, так поедем. – И графиня нагнулась к своему ридикюлю, чтобы скрыть расстроенное лицо. Соня обняла Наташу и поцеловала ее.
Наташа вопросительно взглянула на нее.
– Что ты? Что такое случилось?
– Ничего… Нет…
– Очень дурное для меня?.. Что такое? – спрашивала чуткая Наташа.
Соня вздохнула и ничего не ответила. Граф, Петя, m me Schoss, Мавра Кузминишна, Васильич вошли в гостиную, и, затворив двери, все сели и молча, не глядя друг на друга, посидели несколько секунд.
Граф первый встал и, громко вздохнув, стал креститься на образ. Все сделали то же. Потом граф стал обнимать Мавру Кузминишну и Васильича, которые оставались в Москве, и, в то время как они ловили его руку и целовали его в плечо, слегка трепал их по спине, приговаривая что то неясное, ласково успокоительное. Графиня ушла в образную, и Соня нашла ее там на коленях перед разрозненно по стене остававшимися образами. (Самые дорогие по семейным преданиям образа везлись с собою.)
На крыльце и на дворе уезжавшие люди с кинжалами и саблями, которыми их вооружил Петя, с заправленными панталонами в сапоги и туго перепоясанные ремнями и кушаками, прощались с теми, которые оставались.
Как и всегда при отъездах, многое было забыто и не так уложено, и довольно долго два гайдука стояли с обеих сторон отворенной дверцы и ступенек кареты, готовясь подсадить графиню, в то время как бегали девушки с подушками, узелками из дому в кареты, и коляску, и бричку, и обратно.
– Век свой все перезабудут! – говорила графиня. – Ведь ты знаешь, что я не могу так сидеть. – И Дуняша, стиснув зубы и не отвечая, с выражением упрека на лице, бросилась в карету переделывать сиденье.
– Ах, народ этот! – говорил граф, покачивая головой.
Старый кучер Ефим, с которым одним только решалась ездить графиня, сидя высоко на своих козлах, даже не оглядывался на то, что делалось позади его. Он тридцатилетним опытом знал, что не скоро еще ему скажут «с богом!» и что когда скажут, то еще два раза остановят его и пошлют за забытыми вещами, и уже после этого еще раз остановят, и графиня сама высунется к нему в окно и попросит его Христом богом ехать осторожнее на спусках. Он знал это и потому терпеливее своих лошадей (в особенности левого рыжего – Сокола, который бил ногой и, пережевывая, перебирал удила) ожидал того, что будет. Наконец все уселись; ступеньки собрались и закинулись в карету, дверка захлопнулась, послали за шкатулкой, графиня высунулась и сказала, что должно. Тогда Ефим медленно снял шляпу с своей головы и стал креститься. Форейтор и все люди сделали то же.