I am having a hard time understanding the purpose and significance of NotUsed
and Done
in Akka Streams.
Let us see the following 2 simple examples:
Using NotUsed :
implicit val system = ActorSystem("akka-streams")
implicit val materializer = ActorMaterializer()
val myStream: RunnableGraph[NotUsed] =
Source.single("stackoverflow")
.map(s => s.toUpperCase())
.to(Sink.foreach(println))
val runResult:NotUsed = myStream.run()
Using Done
implicit val system = ActorSystem("akka-streams")
implicit val materializer = ActorMaterializer()
val myStream: RunnableGraph[Future[Done]] =
Source.single("stackoverflow")
.map(s => s.toUpperCase())
.toMat(Sink.foreach(println))(Keep.right)
val runResult: Future[Done] = myStream.run()
When I run these examples, I get the same output in both cases:
STACKOVERFLOW //output
So what exactly are NotUsed and Done? What are the differences and when should I prefer one above the other ?
Akka Streams is a library to process and transfer a sequence of elements using bounded buffer space. This latter property is what we refer to as boundedness and it is the defining feature of Akka Streams. Akka streams consist of three major components in it – Source, Flow and Sink.
By default, Akka Streams will fuse the stream operators. This means that the processing steps of a flow or stream can be executed within the same Actor and has two consequences: passing elements from one operator to the next is a lot faster between fused operators due to avoiding the asynchronous messaging overhead.
Alpakka is based on Akka Streams and provides first class support for streaming—merging streams, splitting streams, and more. It enables use of reactive programming—providing a rich DSL supporting fully asynchronous and non-blocking processing.
Akka Streams is a module built on top of Akka Actors to make the ingestion and processing of streams easy. It provides easy-to-use APIs to create streams that leverage the power of the Akka toolkit without explicitly defining actor behaviors and messages.
First of all, the choice you are making is between NotUsed
and Future[Done]
(not just Done
).
Now, you are essentially deciding the materialized value of your graph, by using the different combinators (to
and toMat
with Keep.right
).
The materialized value is a way to interact with your stream while it's running. This choice does not affect the data processed by your stream, and for this reason you see the same output in both cases. The same element (the string "stackoverflow") goes through both streams.
The choice depends on what your main program is supposed to do after running the stream:
NotUsed
is the right choice. It is just a dummy object, and it conveys the information that no interaction with the stream is allowed nor neededFuture[Done]
. This way you can attach a callback to it using (e.g.) onComplete
or map
.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With