111 lines
4.1 KiB
Scala
111 lines
4.1 KiB
Scala
package docs.stream
|
|
|
|
import akka.NotUsed
|
|
import akka.stream.FlowShape
|
|
import akka.stream.scaladsl.{ GraphDSL, Merge, Balance, Source, Flow }
|
|
import akka.testkit.AkkaSpec
|
|
|
|
class FlowParallelismDocSpec extends AkkaSpec {
|
|
|
|
import GraphDSL.Implicits._
|
|
|
|
case class ScoopOfBatter()
|
|
case class HalfCookedPancake()
|
|
case class Pancake()
|
|
|
|
//format: OFF
|
|
//#pipelining
|
|
// Takes a scoop of batter and creates a pancake with one side cooked
|
|
val fryingPan1: Flow[ScoopOfBatter, HalfCookedPancake, NotUsed] =
|
|
Flow[ScoopOfBatter].map { batter => HalfCookedPancake() }
|
|
|
|
// Finishes a half-cooked pancake
|
|
val fryingPan2: Flow[HalfCookedPancake, Pancake, NotUsed] =
|
|
Flow[HalfCookedPancake].map { halfCooked => Pancake() }
|
|
//#pipelining
|
|
//format: ON
|
|
|
|
"Demonstrate pipelining" in {
|
|
//#pipelining
|
|
|
|
// With the two frying pans we can fully cook pancakes
|
|
val pancakeChef: Flow[ScoopOfBatter, Pancake, NotUsed] =
|
|
Flow[ScoopOfBatter].via(fryingPan1).via(fryingPan2)
|
|
//#pipelining
|
|
}
|
|
|
|
"Demonstrate parallel processing" in {
|
|
//#parallelism
|
|
val fryingPan: Flow[ScoopOfBatter, Pancake, NotUsed] =
|
|
Flow[ScoopOfBatter].map { batter => Pancake() }
|
|
|
|
val pancakeChef: Flow[ScoopOfBatter, Pancake, NotUsed] = Flow.fromGraph(GraphDSL.create() { implicit builder =>
|
|
val dispatchBatter = builder.add(Balance[ScoopOfBatter](2))
|
|
val mergePancakes = builder.add(Merge[Pancake](2))
|
|
|
|
// Using two frying pans in parallel, both fully cooking a pancake from the batter.
|
|
// We always put the next scoop of batter to the first frying pan that becomes available.
|
|
dispatchBatter.out(0) ~> fryingPan ~> mergePancakes.in(0)
|
|
// Notice that we used the "fryingPan" flow without importing it via builder.add().
|
|
// Flows used this way are auto-imported, which in this case means that the two
|
|
// uses of "fryingPan" mean actually different stages in the graph.
|
|
dispatchBatter.out(1) ~> fryingPan ~> mergePancakes.in(1)
|
|
|
|
FlowShape(dispatchBatter.in, mergePancakes.out)
|
|
})
|
|
|
|
//#parallelism
|
|
}
|
|
|
|
"Demonstrate parallelized pipelines" in {
|
|
//#parallel-pipeline
|
|
val pancakeChef: Flow[ScoopOfBatter, Pancake, NotUsed] =
|
|
Flow.fromGraph(GraphDSL.create() { implicit builder =>
|
|
|
|
val dispatchBatter = builder.add(Balance[ScoopOfBatter](2))
|
|
val mergePancakes = builder.add(Merge[Pancake](2))
|
|
|
|
// Using two pipelines, having two frying pans each, in total using
|
|
// four frying pans
|
|
dispatchBatter.out(0) ~> fryingPan1 ~> fryingPan2 ~> mergePancakes.in(0)
|
|
dispatchBatter.out(1) ~> fryingPan1 ~> fryingPan2 ~> mergePancakes.in(1)
|
|
|
|
FlowShape(dispatchBatter.in, mergePancakes.out)
|
|
})
|
|
//#parallel-pipeline
|
|
}
|
|
|
|
"Demonstrate pipelined parallel processing" in {
|
|
//#pipelined-parallel
|
|
val pancakeChefs1: Flow[ScoopOfBatter, HalfCookedPancake, NotUsed] =
|
|
Flow.fromGraph(GraphDSL.create() { implicit builder =>
|
|
val dispatchBatter = builder.add(Balance[ScoopOfBatter](2))
|
|
val mergeHalfPancakes = builder.add(Merge[HalfCookedPancake](2))
|
|
|
|
// Two chefs work with one frying pan for each, half-frying the pancakes then putting
|
|
// them into a common pool
|
|
dispatchBatter.out(0) ~> fryingPan1 ~> mergeHalfPancakes.in(0)
|
|
dispatchBatter.out(1) ~> fryingPan1 ~> mergeHalfPancakes.in(1)
|
|
|
|
FlowShape(dispatchBatter.in, mergeHalfPancakes.out)
|
|
})
|
|
|
|
val pancakeChefs2: Flow[HalfCookedPancake, Pancake, NotUsed] =
|
|
Flow.fromGraph(GraphDSL.create() { implicit builder =>
|
|
val dispatchHalfPancakes = builder.add(Balance[HalfCookedPancake](2))
|
|
val mergePancakes = builder.add(Merge[Pancake](2))
|
|
|
|
// Two chefs work with one frying pan for each, finishing the pancakes then putting
|
|
// them into a common pool
|
|
dispatchHalfPancakes.out(0) ~> fryingPan2 ~> mergePancakes.in(0)
|
|
dispatchHalfPancakes.out(1) ~> fryingPan2 ~> mergePancakes.in(1)
|
|
|
|
FlowShape(dispatchHalfPancakes.in, mergePancakes.out)
|
|
})
|
|
|
|
val kitchen: Flow[ScoopOfBatter, Pancake, NotUsed] = pancakeChefs1.via(pancakeChefs2)
|
|
//#pipelined-parallel
|
|
|
|
}
|
|
|
|
}
|