问题
In Akka
actors, are there any differences - in terms of number of threads being used, or thread locking - between sending a Future
result to another actor by:
A. mapping the Future
to function that tell
the result to the actor.
B. defining an onSuccess
callback on the future, which tell
the result to the actor.
C. piping the Future
result to the actor with pipeTo
.
Some of these options are discussed in a previous question:
Akka: Send a future message to an Actor
Which one of the three is the preferred way to do it, and why?
Also, I would like to know, if receive
should be of type Any => Unit
, then why does the code compile when in some cases the partial function of receive
returns a Future
, not Unit
?
Here is a code example of the three options that I mentioned above:
import akka.actor.{Actor, ActorRef, ActorSystem, Props}
import akka.pattern.ask
import akka.util.Timeout
import akka.pattern.pipe
import scala.concurrent.Future
import scala.concurrent.duration._
import scala.language.postfixOps
import scala.util.Success
class ActorIncrement extends Actor {
def receive = {
case i: Int =>
println(s"increment $i")
sender ! i + 1
}
}
class ActorEven extends Actor {
def receive = {
case i: Int =>
println(s"$i is even")
}
}
class ActorOdd extends Actor {
def receive = {
case i: Int =>
println(s"$i is odd")
}
}
class MyActor(actorIncrement: ActorRef, actorEven: ActorRef, actorOdd: ActorRef) extends Actor {
import scala.concurrent.ExecutionContext.Implicits.global
implicit val timeout = Timeout(5 seconds)
def receive = {
case i: Int if i % 2 == 0 =>
println(s"receive a: $i")
actorIncrement ? i map {
case j: Int =>
println(s"$j from increment a")
actorOdd ! j
}
case i: Int =>
println(s"receive b: $i")
val future: Future[Any] = actorIncrement ? i
future onSuccess {
case i: Int =>
println(s"$i from increment b")
actorEven ! i
}
case s: String =>
println(s"receive c: $s")
(actorIncrement ? s.toInt).mapTo[Int] filter(_ % 2 == 0) andThen { case Success(i: Int) => println(s"$i from increment c") } pipeTo actorEven
}
}
object TalkToActor extends App {
// Create the 'talk-to-actor' actor system
val system = ActorSystem("talk-to-actor")
val actorIncrement = system.actorOf(Props[ActorIncrement], "actorIncrement")
val actorEven = system.actorOf(Props[ActorEven], "actorEven")
val actorOdd = system.actorOf(Props[ActorOdd], "actorOdd")
val myActor = system.actorOf(Props(new MyActor(actorIncrement, actorEven, actorOdd)), "myActor")
myActor ! 2
myActor ! 7
myActor ! "11"
Thread.sleep(1000)
//shutdown system
system.terminate()
}
回答1:
If you look at how pipeTo
is defined in akka.pattern.PipeToSupport
,
def pipeTo(recipient: ActorRef)(implicit sender: ActorRef =
Actor.noSender): Future[T] = {
future andThen {
case Success(r) ⇒ recipient ! r
case Failure(f) ⇒ recipient ! Status.Failure(f)
}
}
}
As you can see... pipeTo
is nothing different than just adding andThen
call to your Future
which either sends the future-result or a Status.Failure
message to the piped actor in case your Future
fails.
Now the main difference lies in this Status.Failure
failure-handling. If you are not using pipeTo
, you can handle your failure in whatever way you want to.
来源:https://stackoverflow.com/questions/47747026/akka-scala-mapping-future-vs-pipeto