以下示例来自akka流参考文档。
import akka.actor.ActorSystem
import akka.stream._
import akka.stream.scaladsl._
/**
* Created by lc on 2016/1/2.
*/
// A shape represents the input and output ports of a reusable
// processing module
case class PriorityWorkerPoolShape[In, Out](
jobsIn: Inlet[In],
priorityJobsIn: Inlet[In],
resultsOut: Outlet[Out]) extends Shape {
// It is important to provide the list of all input and output
// ports with a stable order. Duplicates are not allowed.
override val inlets: scala.collection.immutable.Seq[Inlet[_]] =
jobsIn :: priorityJobsIn :: Nil
override val outlets: scala.collection.immutable.Seq[Outlet[_]] =
resultsOut :: Nil
// A Shape must be able to create a copy of itself. Basically
// it means a new instance with copies of the ports
override def deepCopy() = PriorityWorkerPoolShape(
jobsIn.carbonCopy(),
priorityJobsIn.carbonCopy(),
resultsOut.carbonCopy())
// A Shape must also be able to create itself from existing ports
override def copyFromPorts(
inlets: scala.collection.immutable.Seq[Inlet[_]],
outlets: scala.collection.immutable.Seq[Outlet[_]]) = {
assert(inlets.size == this.inlets.size)
assert(outlets.size == this.outlets.size)
// This is why order matters when overriding inlets and outlets.
PriorityWorkerPoolShape[In, Out](inlets(0).as[In], inlets(1).as[In], outlets(0).as[Out])
}
}
import akka.stream.FanInShape.{Init, Name}
class PriorityWorkerPoolShape2[In, Out](_init: Init[Out] = Name("PriorityWorkerPool"))
extends FanInShape[Out](_init) {
protected override def construct(i: Init[Out]) = new PriorityWorkerPoolShape2(i)
val jobsIn = newInlet[In]("jobsIn")
val priorityJobsIn = newInlet[In]("priorityJobsIn")
// Outlet[Out] with name "out" is automatically created
}
object PriorityWorkerPool {
def apply[In, Out](
worker: Flow[In, Out, Any],
workerCount: Int): Graph[PriorityWorkerPoolShape[In, Out], Unit] = {
FlowGraph.create() { implicit b ⇒
import FlowGraph.Implicits._
val priorityMerge = b.add(MergePreferred[In](1))
val balance = b.add(Balance[In](workerCount))
val resultsMerge = b.add(Merge[Out](workerCount))
// After merging priority and ordinary jobs, we feed them to the balancer
priorityMerge ~> balance
// Wire up each of the outputs of the balancer to a worker flow
// then merge them back
for (i <- 0 until workerCount)
balance.out(i) ~> worker ~> resultsMerge.in(i)
// We now expose the input ports of the priorityMerge and the output
// of the resultsMerge as our PriorityWorkerPool ports
// -- all neatly wrapped in our domain specific Shape
PriorityWorkerPoolShape(
jobsIn = priorityMerge.in(0),
priorityJobsIn = priorityMerge.preferred,
resultsOut = resultsMerge.out)
}
}
}
object ReusableGraph extends App {
implicit val system = ActorSystem("UsingGraph")
implicit val materializer = ActorMaterializer()
val worker1 = Flow[String].map("step 1 " + _)
val worker2 = Flow[String].map("step 2 " + _)
RunnableGraph.fromGraph(FlowGraph.create() { implicit b =>
import FlowGraph.Implicits._
val priorityPool1 = b.add(PriorityWorkerPool(worker1, 4))
val priorityPool2 = b.add(PriorityWorkerPool(worker2, 2))
Source(1 to 10).map("job: " + _) ~> priorityPool1.jobsIn
Source(1 to 10).map("priority job: " + _) ~> priorityPool1.priorityJobsIn
priorityPool1.resultsOut ~> priorityPool2.jobsIn
Source(1 to 10).map("one-step, priority " + _) ~> priorityPool2.priorityJobsIn
priorityPool2.resultsOut ~> Sink.foreach(println)
ClosedShape
}).run()
}
build.sbt
name := "AkkaStream"
version := "1.0"
scalaVersion := "2.11.7"
libraryDependencies ++=Seq(
"com.typesafe.akka" % "akka-actor_2.11" % "2.4.1",
"com.typesafe.akka" % "akka-testkit_2.11" % "2.4.1",
"com.typesafe.akka" % "akka-stream-experimental_2.11" % "2.0-M2"
)
我运行代码,得到如下结果。
step 2 one-step, priority 1
step 2 one-step, priority 3
step 2 one-step, priority 2
step 2 one-step, priority 5
step 2 one-step, priority 4
step 2 one-step, priority 6
step 2 one-step, priority 7
step 2 one-step, priority 8
step 2 one-step, priority 10
step 2 one-step, priority 9
step 2 step 1 job: 2
step 2 step 1 job: 1
step 2 step 1 job: 4
step 2 step 1 job: 6
step 2 step 1 job: 8
step 2 step 1 job: 10
step 2 step 1 priority job: 2
step 2 step 1 priority job: 4
step 2 step 1 priority job: 6
step 2 step 1 priority job: 8
step 2 step 1 priority job: 10
step 2 step 1 job: 3
step 2 step 1 job: 5
step 2 step 1 job: 7
step 2 step 1 job: 9
step 2 step 1 priority job: 1
step 2 step 1 priority job: 3
step 2 step 1 priority job: 5
step 2 step 1 priority job: 7
step 2 step 1 priority job: 9
我有两个问题:
1.步骤2一步到位,是的。
但是&#34;步骤2步骤1工作&#34;应该在&#34;第2步第1步优先工作&#34;之后,为什么它出现在&#34;第2步第1步优先工作&#34;?
2.只有一个工人实例,工人部分会同时运行吗?
答案 0 :(得分:0)
问题有点老,但无论如何都要回答,因为我偶然发现了同样的事情。
我认为这只是因为你的电脑足够快,一旦它碰到这个代码:
Source(1 to 10).map("job: " + _) ~> priorityPool1.jobsIn
Source(1 to 10).map("priority job: " + _) ~> priorityPool1.priorityJobsIn
在发送第二个10个数字时,前10个已经处理完毕。我认为由于这个问题,他们将示例更改为100,但仍然在我的计算机上,我看到的结果与您的相似,但如果您使用限制减慢速度,您将看到结果如何期望它们:
Source(1 to 10)
.throttle(1, 0.1.second, 1, ThrottleMode.shaping)
.map("job: " + _) ~> priorityPool1.jobsIn
Source(1 to 10)
.throttle(1, 0.1.second, 1, ThrottleMode.shaping)
.map("priority job: " + _) ~> priorityPool1.priorityJobsIn
所以,并不是说结果不正确,只是并行处理你的电脑可能太快了。
当然,这里的限制仅用于减慢计算速度并使我们的学习示例正常工作,不应该用于生产,除非减慢计算实际上是你想要的。