アッカ(17):ストリーム:基本的なデータフローコンポーネント-Source、フロー、シンクの紹介

 ビッグデータ番組では人気の今日、多くのプログラムは、一般的な問題に直面している:プログラム入力データは、無限大に到着し、不確実な時間を傾向があります。一般的な解決策を達成するためのコールバック関数(コールバック関数)を使用することですが、そのような解決策は、おそらく「コールバック地獄(コールバック地獄)」、いわゆる「後藤-地獄」が発生することです:プログラム制御をジャンプでコールバック関数の変化ならば困難なトラックは、特に変数のいくつかは、予測できない結果を持っています。データストリーム(ストリーム)プログラムは、問題を解決するための効果的な方法です。ストリームは抽象的な概念であり、プログラムはデータ処理の仕方によって、隠された入力データやその他の詳細を処理することができます簡単に理解するために、全トレースプログラムのロジックを記述し確認しました。もちろん、操作の詳細の一部をコントロールする能力を犠牲に。私たちは前にscalazストリームを導入し、その主な相違点のアッカストリーム:

1、scalazストリームは、プル・モードであり、プッシュアッカストリームモードです。この手順で(ポーリング)ポート入力データが存在するかどうかを検出するパターンで繰り返さなければならないので不利な点は、効率を受け取るプルモデルデータです。プッシュモードは、直接プログラムに入力ポートにデータをプッシュしますが、ソースデータの移動が速すぎてタイムリーに押されて、データが不足して、すべてのデータを処理できない場合には、いわゆるデータのオーバーフローが発生します。しかし、アッカ・ストリーム仕様の背圧反応ストリームを達成するために:送信者と受信者のデータ間のヒント相互作用するので、過度のデータが受信パーティによって生成され、遅くすることができ、あるいは一時的に停止すること。

2、scalaz-sstream提供アッカストリームデータフローと処理フローデータの宣言的記述の一種であり、それはプログラム動作に属し、最終的に与えるためにプログラムを計算することにより、特定のデータストリームにいくつかの演算を実行する必要が副作用と計算結果。scalazストリーム操作は、スレッドを使用することを特徴と自己完結型の機能的なプログラムは、十分に制御することが可能であり、並列計算。アッカ・ストリーム操作がmaterializerです。メッセージ駆動型、クラスタコンピューティング、規制政策(SupervisorStrategy)と同じように:システム上で実行されている俳優materializer、俳優であっモードプログラムの利点を含んでいます。

アッカストリームデータフローは、一緒に3つの基本的な構成要素の組み合わせである機能および発現を処理する異なるデータの異なる組み合わせを表します。三つのコンポーネントは次のとおりです。

1、ソース:データソース。アッカ・ストリームがプッシュモードに属し、ソースはソース形状SourceShape一つだけの出力ポート形状に代わって、パブリッシャ(データ・パブリッシャ)です。単一の値、セット、またはいくつかの他のデータストリーム生成パブリッシャ要素データストリーム(ストリーム要素)からのソースは、前記します

  / **
   *ヘルパーIterable` `から[[ソース]]を作成します。
   *使用例: `ソース(配列(1,2,3))`
   *
   *与えられた`Iterable`から新しい` Source`を開始します。これはから始まるようである
   *イテレータが、すべての加入者が直接のパブリッシャに接続
   (常にから始まる要素の個々のフローが表示されます*ストリーム
   かかわらず、彼らが加入したときの*初めに)。
   * /
  DEF [T]適用(反復可能:immutable.Iterable [T]):ソース[T、NOTUSED] =
    単一(反復可能).mapConcat(ConstantFun.scalaIdentityFunction).withAttributes(DefaultAttributes.iterableSource)
 
  / **
   * `の作成一つの要素とSource`。
   *すべては`このストリームのSink`は、一つの要素からなる個々のストリームが表示されます接続しました。
   * /
  DEF単[T](エレメント:T):ソース[T、NOTUSED] =
    fromGraph(新しいGraphStages.SingleSource(エレメント))
 
  / **
   *ヘルパー作成する[出典] Iterator` `から。
   *使用例: `Source.fromIterator(()=> Iterator.from(0))`
   *
   *スタートanIteratorを生成する所与の機能から新しい`Source`。
   *イテレータが空に実行されるまでの元素の生成ストリームが続く
   *をまたは`次の()`メソッドの評価中に失敗しました。
   *要素は、需要が来るに従ってイテレータから引き出される
   下流変換ステップから*。
   * /
  DEF fromIterator [T](F:()⇒イテレータ[T]):ソース[T、NOTUSED] =
    (新しいimmutable.Iterable [T] {適用
      オーバーライドDEFイテレータ:イテレータ[T] = F()
      DEFオーバーライドtoString:文字列= "()=>イテレータ"
    })
 
  / **
   *指定された`Future`から新しい` Source`を開始します。ストリームが構成されます
   `Future`が成功した値で終了したとき* 1要素
   *前または` Flow`を実体化した後に発生する可能性があります。
   `Future`が失敗して終了した場合*ストリームは、失敗して終了します。
   * /
  DEF fromFuture [T](未来:未来[T]):ソース[T、NOTUSED] =
    fromGraph(新しいFutureSource(未来))
 
  / **
   *ヘルパーPublisher` `から[[ソース]]を作成します。
   *
   *与えられた出版社で始まる変換を構築します。変換ステップは、
   *の一連によって実行される[[org.reactivestreams.Processor]インスタンス
   *下流エレメントの流れの伝播媒介する
   *背圧上流。
   * /
  DEF fromPublisher [T](出版社:出版社[T]):ソース[T、NOTUSED] =
    fromGraph(新しいPublisherSource(出版社、DefaultAttributes.publisherSource、形状( "PublisherSource")))
 
  / **
   *グラフと元の形状は、論理的には、この方法が作る、ソースです
   *そうもタイプインチ
   * /
  DEF fromGraph [T、M](G:グラフ[SourceShape [T]、M]):ソース[T、M] = Gマッチ{
    ケースS:ソース[T、M]⇒S
    ケースS:javadsl.Source [T 、M]⇒s.asScalaの
    場合、他⇒新しいソース(
      LinearTraversalBuilder.fromBuilder(other.traversalBuilder、other.shape、Keep.right)、
      other.shape)
  }

下面还有几个特殊的出典:
  / **
   * A `Source`なしの要素、すなわち、すべての接続` Sink`ためにすぐに終了した空のストリームを持ちます。
   * /
  DEF空にする[T]:ソース[T、NOTUSED] = _empty
  プライベート[この]ヴァル_empty:ソース[何も、NOTUSED] =
    Source.fromGraph(EmptySource)
 
  / **
   *は、継続的に放出する`Source`を作成します。要素を与えられました。
   * /
  DEFリピート[T](エレメント:T):ソース[T、NOTUSED] = {
    ヴァル次=一部((要素、要素))
    展開](素子)(_⇒次).withAttributes(DefaultAttributes.repeat)
  }
 
  / **
   *指定された順序で指定した要素を継続的に生み出すこと[[ソース]]作成します。
   *
   *与えられた要素から新しい「循環」 `Source`を開始します。要素の生産ストリームは
   *関数のパラメータによって提供される要素のシーケンスを繰り返すことにより、無限に続けます。
   * /
  DEFサイクル[T](F:()⇒イテレータ[T]):ソース[T、NOTUSED] = {
    iが(fは=ヴァル反復子= Iterator.continually {ヴァル)。もしそうでなければ(i.isEmpty)新しいIllegalArgumentExceptionをスローし( "イテレータを空にする")は、i} .flatten
    fromIterator(()⇒イテレータ).withAttributes(DefaultAttributes.cycledSource)
  }

2、シンク:データ端末。消費者に属するデータ要素は、主な役割は、消費データストリーム要素です。SinkShapeは、入力された形状データストリームを有しています。:例シンクストリーム要素が消費される
  / **
   ストリームザ・エレメントと廃棄を消費する* A `Sink`。
   * /
  DEF無視:シンク[でも、将来[完了] = fromGraph(GraphStages.IgnoreSink)
 
  / **
   Sink` A `*起動手順の各要素のための受信与えられた。シンクaのがISマテリアライズドという意志
   * INTO Aをた`到達すると、[[scala.concurrent.Future]]がSUCCESS`に完成予定
   ストリームの*ノーマルザ・終了、または`Failure`がでシグナリングにIS Aの故障を完了とがIF
   ストリーム* ..
   * /
  DEF foreachの[T](F:T⇒単位):シンク[T、将来[完了] =
    流量[T] .MAP(F ).toMat(Sink.ignore)(Keep.right) .named( "foreachSink")

なお、アッカ・ストリーム動作は実際の俳優で行われます。アクター内部状態計算の結果は、最終的に形成されてもよいです。上記の例の演算結果がシンク将来[??]タイプが得られます。
図3に示すように、フローデータ処理ノード。入力データストリーム入力ポート行うの要素の後に出力ポートを介して処理(変換)をシフトします。FlowShapeは、入力と出力を持っています。

アッカ・ストリーム内のデータ・フロー・グラフ内のコンポーネントのデータストリームは、一般的に(グラフ)と呼ばれます。我々は、より大きなストリーム・グラフの形図を流れて大量のデータを使用することができます。

データストリーム(線形ストリーム)線形無傷(または閉)最も単純なアッカストリームは、ソースとシンクと直接接触しています。source.runWith(Sink.foreach(のprintln)):このように、データストリームのようなすべての要素の直接の発現を表します。私たちは、Source.to接続シンクで、フローを接続するためにSource.viaを使用することができます。

  オーバーライドDEFを介し[T、MAT2](フロー:グラフ[FlowShape [うち、T]、MAT2):REPR [T] = viaMat(フロー)(Keep.left)
 
  viaMat [T、MAT2、MAT3](フローDEFオーバーライド:グラフ[FlowShape [うち、T]、MAT2])(コンバイン:(マット、MAT2)⇒MAT3):ソース[T、MAT3] = {
    ヴァルtoAppend =
      IF(flow.traversalBuilder当Flow.identityTraversalBuilder)
        LinearTraversalBuilder.empty( )
      他の
        flow.traversalBuilder
 
    新しいSource [T、MAT3](
      traversalBuilder.append(toAppend、flow.shape、コンバイン)、
      SourceShape(flow.shape.out))
  }
 
  / **
   *接続し、この[[akka.stream.scaladsl。ソース]] [[akka.stream.scaladsl.Sink]]に、
   *両方の処理ステップを連結します。
   * /
  DEF [MAT2]に(シンク:グラフ[SinkShape [OUT]、MAT2):RunnableGraph [マット] = toMat(シンク)(Keep.left)
 
  / **
   *接続この[[akka.stream.scaladsl.Source] [akka.stream.scaladsl.Sink]、
   *両方の処理ステップを連結します。
   * /
  DEF toMat [MAT2、MAT3](シンク:グラフ[SinkShape [OUT]、MAT2])(コンバイン:(マット、MAT2)⇒MAT3):RunnableGraph [MAT3] = {
    RunnableGraph(traversalBuilder.append(sink.traversalBuilder、 sink.shape、コンバイン))
  }

これは、経由してtoMatにviaMatと速記はKeep.leftを固定している見つけることができます。計算結果の左側のデータフロー図を選択することを意味します。我々は、アッカストリーム上記システム俳優の要素を処理するデータのストリームです。このプロセスでは、アクターの内部状態は、演算結果を生成するために使用されてもよいです。左右のグラフ、及び左のグラフの選択された演算結果を介して接続します。私たちは、操作の右のグラフの結果を選択することviaMatとtoMatを使用することができます。(マット、MAT2)=:これは組み合わせによって達成される > MAT3 この機能の実装。キープを提供するために、アッカ・ストリームオブジェクトは、この選択を表現:
/ **
 多くの場合、フィールドのようなだけ遭遇した目的を維持するための*便利な機能
 。*二つの入力値のみまたは右(SECOND)(第一)左
 * /
オブジェクトキープ{
  プライベートヴァル_Left =(L:任意、R&LT:任意)⇒L
  プライベートヴァル_right =(L:任意、R&LT:任意)⇒R&LT
  専用ヴァル_both =(L:任意、R&LT:任意)⇒(L、R&LT)
  ヴァルの_none =プライベート(L:任意、R&LT:任意)⇒NOTUSED
 
  DEF [L、R&LT]左(L、R&LT)_left.asInstanceOf⇒L = [(L、R&LT)⇒L]
  DEF右[L、R]:(L、R)⇒R = _right.asInstanceOf [(L、R)⇒R]
  DEF [L、R]の両方:(L、R)⇒(L、R)= _both。 asInstanceOf [(L、R)⇒(L、R)]
  DEFなし[L、R]:(L、R)⇒NOTUSED = _none.asInstanceOf [(L、R)⇒NOTUSED]
}

:演算結果の取り扱い説明したように、我々は、Sourceは、フロー、シンクのパラメータの種類を見てみましょう
ソース[+アウトは、+マットは] //アウト代表要素タイプ、マットは、操作タイプの結果である
フロー[-In、+アウト、+マット] // IN、OUTは、マットは操作タイプの結果であり、要素タイプデータストリームである
シンク[-In、+マット] //でデータ要素タイプ、マットタイプの演算結果であります


キープオブジェクトは、マットの選択を提供します。、関数リターン結果toMatに上記ソースコードは、シンクに接続されているRunnableGraph [MAT3]は、データストリームを算出しています。RunnableGraph実行()関数は、データストリームを計算します。

/ **
 *添付の入力と出力を持つフローは、実行することができます。
 * /
最終ケースクラスRunnableGraph [+マット](オーバーライドヴァルtraversalBuilder:TraversalBuilder)はグラフ[ClosedShape、マット] {延び
  オーバーライドDEF形状= ClosedShape
 
  / **
   *彼らがいたように、すべての他の特性を残し、このRunnableGraphのみマテリアライズド値を変換します。
   * /
  DEF mapMaterializedValue [MAT2](F:マット⇒MAT2):RunnableGraph [MAT2] =
    コピー(traversalBuilder.transformMat(f.asInstanceOf [どれ⇒任意]))
 
  / **
   *を実行し、このフローからマテリアライズド・インスタンスを返しますフロー。
   * /
  DEF実行()(暗黙のmaterializer:Materializer):マット= materializer.materialize(この)
...


上記形状は、平均ClosedShape =代表RunnableGraphが閉じられた形状(ClosedShape)である:すべての入力1つの出力ポートを実行しているグラフは、接続しなければなりません。
ここでは詳細な説明を行うために、単純な線形データ・ストリームを使用します。

akka.actor._インポート
akka.stream._インポート
akka.stream.scaladsl._インポート
akka._インポート
インポートscala.concurrent._の
 
オブジェクトSourceDemoアプリ{延び
  暗黙ヴァルSYS = ActorSystem(「デモ」)を
  暗黙ヴァルマット= ActorMaterializer ()
  暗黙ヴァルEC = sys.dispatcher
 
  ヴァルS1:ソース[INT、NOTUSED] =ソース(1〜10)
  ヴァルシンク:シンク[でも、今後は[完了] = Sink.foreach(のprintln)
  ヴァルRG1:RunnableGraph [NOTUSED ] = s1.to(シンク)
  ヴァルRG2:RunnableGraph [未来[完了] = s1.toMat(シンク)(Keep.right)
  ヴァルRES1:NOTUSED = rg1.run()
 
  のThread.sleep(1000)
 
  ヴァルRES2:未来[完了] = rg2.run()
  res2.andThen {
    ケース_ => sys.terminate()
  }
  
}


我々は、特に上述のタイプの結果に焦点を当てる:操作のソース・タイプは、マットNOTUSEDの結果であり、演算結果のシンクマットタイプが将来[完了]です。私たちは、シンク今後は動作終了ノードをキャプチャするために[完了]操作の結果を返すことを選択しtoMatと上記のコードから参照してください。以下の実施例は、さらに行動のいくつかの組み合わせを含む:
  ヴァル= SEQ配列[INT](1,2,3)
  DEF toIteratorを()= seq.iterator
  ヴァルもつFlow1:フロー[INT、INT、NOTUSED] =フローの[int]。マップ(+ _ 2)
  ヴァルFlow2:フロー[INT、INT、NOTUSED] =流量[INT] .MAP(_ * 3)
  ヴァルSource.fromIterator S2 =(toIterator)
  ヴァル++ S1 S2 S3 =
 
  ヴァルS4:ソース[ INT、NOTUSED] = s3.viaMat(もつFlow1)(Keep.right)
  ヴァルS5:ソース[INT、NOTUSED] = s3.via(もつFlow1).async.viaMat(Flow2)(Keep.right)
  ヴァルS6:ソース[INT 、NOTUSED] = s4.async.viaMat(Flow2)(Keep.right)
  (s5.toMat(シンク)(Keep.right).RUN())。ケースandthen {_ => sys.terminate()}

一般に、データストリーム要素はアクター1内のすべてのプロセス(工程-定着)のために結合され、メッセージ俳優の間だけでなく、要素の処理のパラレルデータを制限するように除去することができます。aync役割は、独立した俳優で実行するために、グラフの左側を指定することです。注:S6 = S5。
ソースフローへの接続新しいソースを形成する:例から、我々はのタイプを合わせた結果があることを見つけるの上。

私たちは、次のようにソースは、砂糖直接計算されたデータ・ストリームを提供アッカ・ストリーム事実を使用することがあります。

  s1.runForeach(のprintln)
  ヴァルFRES = s6.runFold(0)(_ _ +)
  fres.onSuccess {ケースA =>のprintln()}
  fres.andThen {ケース_ => sys.terminate()}

出典以下ランナーのいくつかは以下のとおりです。

 / **
   *折り機能で、この`Source`を実行するためのショートカット。
   *所定の機能はそれにその前与え、すべての受信素子のために呼び出される
   *出力(又は所与`zero`値)を入力として要素。
   *返さ[scala.concurrent.Future]最終の値で終了する
   場合、入力ストリームが終了する*機能の評価、または`Failure`で完了
   ストリームでシグナリング障害がある場合*。
   * /
  DEF runFold [U](ゼロ:U)(F:(U、アウト)⇒U)(暗黙materializer:Materializer):将来[U] = runWith(Sink.fold(ゼロ)(F))
 
  / **
   * foldAsync機能で、この`Source`を実行するためのショートカット。
   *所定の機能はそれにその前与え、すべての受信素子のために呼び出される
   *出力(又は所与`zero`値)を入力として要素。
   *返さ[scala.concurrent.Future]最終の値で終了する
   場合、入力ストリームが終了する*機能の評価、または`Failure`で完了
   ストリームでシグナリング障害がある場合*。
   * /
  DEF runFoldAsync [U](ゼロ:U)(F:(U、アウト)⇒将来[U])(暗黙materializer:Materializer):将来[U] = runWith(Sink.foldAsync(ゼロ)(F))
 
  / **
   *減らす機能と、この`Source`を実行するためのショートカット。
   *与えられた機能はそれにその以前を与えて、受信したすべての要素に対して呼び出されます
   *(第2要素)からの出力とを入力として要素。
   *返さ[scala.concurrent.Future]最終の値で終了する
   場合、入力ストリームが終了する*機能の評価、または`Failure`で完了
   ストリームでシグナリング障害がある場合*。
   *
   *ストリームは(任意の要素を知らせる前に、すなわち完了)空である場合は、
   * [[はNoSuchElementException]]、とその下流に失敗する段階を減らすこと
   で、ラインScalaの標準ライブラリのコレクションがあることと、意味的である*
   *このような状況で行います。
   * /
  DEF runReduce [U>:アウト(F:(U、U)⇒U)(暗黙materializer:Materializer):将来[U] =
    runWith(Sink.reduce(F))
 
  / **
   * foreachの手順でこの`Source`を実行するためのショートカット。所定の手続きが起動され
   、各受信素子のため*。
   *返さ[scala.concurrent.Future]が到達したときSUCCESS` `で完了される
   ストリームの*正常終了、またはでシグナリング障害が発生した場合` Failure`で完了
   ストリーム*は。
   * /
  // FIXME:アウト=>ユニットは、右滞在する必要があります?
  DEF runForeach(F:アウト⇒ユニット)(暗黙materializer:Materializer):将来[完了] = runWith(Sink.foreach(F))

它们的功能都是通过runWith实现的:
 / **
   `Sink`へ*接続し、この` Source`し、それを実行します。返される値は、値をマテリアライズされた
   [[akka.stream.scaladsl.Sink番号の発行者]]の`Sink`、例えば` Publisher`の*。
   * /
  DEF runWith [MAT2](シンク:グラフ[SinkShape [OUT]、MAT2])(暗黙materializer:Materializer):MAT2 = toMat(シンク)(Keep.right).RUN()

実際にクラスシンクに対応する方法を使用してシンク。???。
以下は、例示的なソースコードです。

akka.actor._インポート
akka.stream._インポート
akka.stream.scaladsl._インポート
akka._インポート
インポートscala.concurrent._の
 
オブジェクトSourceDemoアプリ{延び
  暗黙ヴァルSYS = ActorSystem(「デモ」)を
  暗黙ヴァルマット= ActorMaterializer ()
  暗黙ヴァルEC = sys.dispatcher
 
  ヴァルS1:ソース[INT、NOTUSED] =ソース(1〜10)
  ヴァルシンク:シンク[でも、今後は[完了] = Sink.foreach(のprintln)
  ヴァルRG1:RunnableGraph [NOTUSED ] = s1.to(シンク)
  ヴァルRG2:RunnableGraph [未来[完了] = s1.toMat(シンク)(Keep.right)
  ヴァルRES1:NOTUSED = rg1.run()
 
  のThread.sleep(1000)
 
  ヴァルRES2:未来[完了] = rg2.run()
  res2.andThen {
    ケース_ => //sys.terminate()
  }
 
  ヴァル配列=配列[INT](1,2,3)
  toIterator()= seq.iterator DEF
  フロー[INT、INT、NOTUSED] =流量[INT] .MAP(_ + 2):valをもつFlow1
  ヴァルflow2:フロー[INT、INT、NOTUSED] =流量[INT] .MAP(_ * 3)
  ヴァルS2 = Source.fromIterator(toIterator)
  ヴァルS3 = S1 ++ S2
 
  ヴァルS4:ソース[INT、NOTUSED] = s3.viaMat(もつFlow1 )(Keep.right)
  ヴァルS5:ソース[INT、NOTUSED] = s3.via(もつFlow1).async.viaMat(flow2)(Keep.right)
  ヴァルS6:ソース[INT、NOTUSED] = s4.async.viaMat( flow2)(Keep.right)
  (s5.toMat(シンク)(Keep.right).RUN())。andThen {ケース_ =>} //sys.terminate()}
 
  s1.runForeach(のprintln)
  ヴァルFRES = S6 .runFold(0)(_ _ +)
  fres.onSuccess {ケースA =>のprintln()}
  ケース_ = {fres.andThen> sys.terminate()}
  
}
--------------------- 
TIGER_XC:の 
ソース:CSDNを 
記述します。https://ブログ。 csdn.net/TIGER_XC/article/details/77159545 
免責事項:この記事はブロガーオリジナル記事ですが、ボーエンのリンクを添付してください、再現しました!

リリース6元記事 ウォン称賛43 ビュー570 000 +

おすすめ

転載: blog.csdn.net/hany3000/article/details/83620197