13

I'm currently working on a project that extensively uses Akka and Akka Streams.

One question/problem keeps coming up while working with it: What is the best practice for the Materializer which is needed in all places where streams are used. Especially when I'm inside an Actor, where I only can access the ActorSystem, should I manually pass in an existing Materializer instance or just create one when I need it?

I'm especially worried about the resource usage and performance when instantiating Materializers on demand.

Alexander Block
  • 2,025
  • 1
  • 10
  • 11

1 Answers1

16

The creation of ActorMaterializers is fairly cheap and having a reasonable proliferation of them shouldn't be an issue in the majority of cases.

If you chase the chain of calls starting from ActorMaterializer.apply (see source code) you'll find that ActorMaterializer (or better, ActorMaterializerImpl) is not performing anything significant at creation time.

Just to give you an idea of how it compares to an ActorSystem creation, consider the following code

  val sysStart = System.nanoTime()
  val actorSystem = ActorSystem("mySystem")
  val sysDuration = FiniteDuration(System.nanoTime() - sysStart, TimeUnit.NANOSECONDS)
  println(s"System creation: ${sysDuration.toMillis} ms")

  val matStart = System.nanoTime()
  val materializer = ActorMaterializer()(actorSystem)
  val matDuration = FiniteDuration(System.nanoTime() - matStart, TimeUnit.NANOSECONDS)
  println(s"Materializer creation: ${matDuration.toMillis} ms")

outputs this on my laptop

System creation: 901 ms

Materializer creation: 14 ms

However, as Johan pointed out in the comments, it is important to add that materializers' lifecycle needs to be properly managed, invoking shutdown whenever they stop being useful, to avoid leaking resources.

To recap, passing a materializer around whenever possible is a sound choice. Whenever this is not convenient though, its creation is cheap, but pay attention to shut it down properly.

Community
  • 1
  • 1
Stefano Bonetti
  • 8,973
  • 1
  • 25
  • 44
  • I think lifecycle and lifecycle management is more important than performance. If you `shutdown` a materializer all its running streams are abruptly terminated, if you create a materializer in an actor and do not shut it down when you are stopping the actor you are leaking resources. – johanandren Apr 26 '17 at 07:12
  • 1
    Definitely agree with that, and anyway performance is not massively skewed with either of the 2 choices. `mat.shutdown()` should always be included in the `postStop` method of your actor. – Stefano Bonetti Apr 26 '17 at 07:49