Akka Streamsは非同期処理のオーバーヘッドを避けるため、デフォルトでStageを処理する時は順番で一つづつで処理していく。
しかし、複数のStageを非同期処理したい場合も必ずある。その時は async メソッドを使う。
async をつけたStageは一つ単独のActorで実行される。一方、付けてないStageは全部もう一つのActorで実行される。
以下、2つのフライパンでパンケーキを作る例を通して、非同期処理の2つのやり方を紹介する。
Pipelining
まずはPipelining方式、2つのフライパンを違う工程をし、順番で行う方式。
一つのフライパンは生のパンケーキの片面を焼く、もう一つのフライパンは半分焼いたパンケーキのもう一面を焼く。
1 | // Takes a scoop of batter and creates a pancake with one side cooked |
この方式は、主に依存しているStageを非同期で処理する時に使う。
上記の例では、fryingPan2はfryingPan1の結果を依存しているが、非同期処理するので、fryingPan2が処理する時は、fryingPan1が次のパンケーキの処理に入れる。
Parallel
まずはParallel方式、2つのフライパン同時に同じ工程を行う方式。
2つのフライパンは生のパンケーキの両面を焼く。
1 | val fryingPan: Flow[ScoopOfBatter, Pancake, NotUsed] = |
この方式は、主に依存していないStageを非同期で処理する時に使う。
メリットとしてはスケールアップしやすい、同じ工程で三つ目のフライパンにの出来る。
正しい結果の順番が保証されないので、注意が必要。
順番を保証したい場合は、こちらの例を参照。
Combining pipelining and parallel processing
勿論、2つ方式を合成することも出来る。
まずはpipelining処理を2つparallelに合成。
1 | val pancakeChef: Flow[ScoopOfBatter, Pancake, NotUsed] = |
この方式はフライパンを焼くような工程を相互影響しない場合に適用。
次はparallelな処理を2つのpipeliningに合成。
1 | val pancakeChefs1: Flow[ScoopOfBatter, HalfCookedPancake, NotUsed] = |
まとめ
以上、Stageに関して説明はここまで、適切なStageを扱うことで、データを思うように操る事ができるでしょう。
Stageは流れで処理するので、処理の順番が保証される。
非同期処理にする方法もあります。