Что означает материализованное значение и почему оно отличается в приведенной ниже логике для одного и того же графика?

Я новичок в Akka Stream и только на прошлой неделе начал читать его документы. Я могу понять большинство концепций, но мне трудно понять, что означает Materialized Value в потоке Akka и каково его значение?

Если бы кто-нибудь мог объяснить мне это на примере из реального мира, это очень помогло бы связать его и его варианты использования в Akka Stream.

Обновить

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

  implicit val system = ActorSystem("PlainSinkProducerMain")
  implicit val materializer = ActorMaterializer()
  val source = Source(1 to 10)
  val sink = Sink.fold[Int, Int](0)(_ + _)
  val runnable: RunnableGraph[Future[Int]] =
  source.toMat(sink)(Keep.right)
  val sum1: Future[Int] = runnable.run()
  val sum2: Future[Int] = runnable.run()
   println(sum1.value)
   println(sum2.value)

Когда я запускаю это, я получаю вывод ниже:

None
Some(Success(55))

Приведенный выше пример взят из документов. и ниже пояснение к этому.

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

У меня есть 2 вопроса: 1) Почему 2 разных материализованных экземпляра одного и того же графа имеют 2 разных выходных значения? Хотя материализованное значение вычисляется дважды, но под капотом оба расчета относятся к одному и тому же графику.

2) Почему тип возврата Some(Success(55)) вместо обычного 55 для успешного выполнения и Failure Exception для неудачных случаев? (Это могут быть глупые вопросы, но я хочу понять, какую проблему/преимущество решает/дает это специальное возвращаемое значение.)


person Explorer    schedule 03.08.2017    source источник
comment
Возможный дубликат Akka Streams: что представляет Mat в Source[out , мат]   -  person Vladimir Matveev    schedule 03.08.2017
comment
@VladimirMatveev Спасибо за ваш комментарий, я прочитал ваше объяснение, и это было действительно полезно. Из вашего объяснения я понял, что Future[Int] говорит, что материализация графа даст целочисленное значение в будущем, если оно завершится успешно, или выдаст сообщение об ошибке. Я хочу знать, что послужило мотивом для этого дизайна? и почему простое сообщение об успехе и неудаче не было выброшено? Это потому, что он работает Asynchronously, а другая задача будет использовать значение Future[Int], чтобы определить, произошла ли какая-либо ошибка или нет в определенный момент времени «T»?   -  person Explorer    schedule 03.08.2017
comment
Наконец, если у вас есть дополнительные вопросы, на stackoverflow нужно создавать для них отдельные темы.   -  person Vladimir Matveev    schedule 03.08.2017
comment
Therefore, even if the stream terminates immediately, it is not guaranteed that the value will be available immediately эта строка объясняет причину наличия Future[Int]. Спасибо и за другие комментарии, которые очень помогли понять преимущества дизайна, которые дает Akka Stream.   -  person Explorer    schedule 03.08.2017
comment
@VladimirMatveev Если вы можете поместить все эти комментарии в раздел ответов, я могу отметить его как правильный ответ, поскольку он ответил на все мои сомнения.   -  person Explorer    schedule 03.08.2017
comment
Сделанный. Ответы оказались длиннее, чем я ожидал :)   -  person Vladimir Matveev    schedule 03.08.2017


Ответы (1)


(ответ на комментарий) Я не уверен, что полностью понимаю ваш вопрос, но в целом потоки асинхронны, и когда вы выполняете run() для материализации потока, он начинает выполняться в другом пуле потоков. Таким образом, даже если поток немедленно завершится, не гарантируется, что значение будет доступно немедленно. Вот почему результатом Sink.fold является Future[T] - фьючерсы означают значения, которые будут доступны "в будущем", и это именно та семантика, которая здесь нужна.

"почему... иметь 2 разных значения" - именно из-за асинхронности. В вашем случае получилось так, что второе будущее завершилось до того, как вы его заметили, а первое нет. Если вы запустите эту программу несколько раз, скорее всего, вы получите разные результаты.

"почему тип возвращаемого значения Some(Success(55))..." ну, так устроены фьючерсы в Scala. Метод Future.value возвращает Option[Try[T]], то есть возвращает None, если будущее не завершено в момент вызова, и Some(v), если оно завершено, где v равно Success(result) или Failure(throwable). В общем, в Scala идиоматично рассматривать ошибки как значения, а не исключения, которые неявно развертывают стек вызовов при возникновении.

Обратите внимание, что обычно вы не используете Future.value при работе с фьючерсами. Обычно вы преобразуете futures с помощью комбинаторов, таких как map, flatMap или Future.sequence, а затем либо передаете результат окончательно преобразованного future в какую-либо библиотеку (например, в виде HTTP-ответа в веб-фреймворке), либо используете такой метод, как Await.result(future, timeout), чтобы получить окончательный результат будущее или исключение, если будущее не завершено в течение указанного периода времени.

person Vladimir Matveev    schedule 03.08.2017
comment
С помощью `println(Await.result(sum1, Duration(200,MILLISECONDS)))` я получил окончательный результат как 55 :) - person Explorer; 03.08.2017