title: akka stream parallelism and performance
body: <p>I am learning akka streams and I am not sure to fully understand the performance difference between these 2 codes when running on my laptop with 2 cores and 8 GB of RAM.</p>
  
  <pre><code>val f = Source(1 to numberOfFiles)
      .mapAsyncUnordered(numberOfFiles) { _ =&gt;
        val fileName = UUID.randomUUID().toString
        println(fileName)
        Source(1 to numberOfCustomers).mapAsyncUnordered(numberOfCustomers){ _ =&gt;
          val rMsisdn = TestUtils.randomString(8)
          Future(List(1 to Random.nextInt(20)).map{ i=&gt;
            val rCdr= RandomCdr(rMsisdn)
            ByteString(s"${rCdr.msisdn};${rCdr.dateTime};${rCdr.peer};${rCdr.callType};${rCdr.way};${rCdr.duration}\n")
          }.fold(ByteString())(_ concat _))
        }.runWith(FileIO.toPath(Paths.get(s"/home/reactive/data/$fileName")))
      }
      .runForeach(io=&gt; println(io.status))
  </code></pre>
  
  <p>and this one:</p>
  
  <pre><code>  val f = Source(1 to numberOfFiles)
      .mapAsyncUnordered(numberOfFiles) { _ =&gt;
        val fileName = UUID.randomUUID().toString
        println(fileName)
        Source(1 to numberOfCustomers).map{ _ =&gt;
          val rMsisdn = TestUtils.randomString(8)
          List(1 to Random.nextInt(20)).map{ i=&gt;
            val rCdr= RandomCdr(rMsisdn)
            ByteString(s"${rCdr.msisdn};${rCdr.dateTime};${rCdr.peer};${rCdr.callType};${rCdr.way};${rCdr.duration}\n")
          }.fold(ByteString())(_ concat _)
        }.runWith(FileIO.toPath(Paths.get(s"/home/reactive/data/$fileName")))
      }
      .runForeach(io=&gt; println(io.status))
  </code></pre>
  
  <p>The second one provides better performance and the difference is going more and more important with more load (more files to write and customers to generate).
  My assumptions is that the random generation is not so complicated, so parallelizing it with mapAsync has a higher cost than just running it sequentially. Am I right ?
  What I don't understand is the fact that the difference increase with the number of customer. The more I have the higher the difference is between sequential generation and parallel generation.</p>
  
  <p>Is it also coming from the fact that I have a stream in a stream ? Is it inefficient to have 2 levels of parallelism one in another ?</p>
  
  <p>Thanks for your explanation and if you have any suggestion to tune this code don't hesitate !</p>
  
  <p><strong>Edit</strong></p>
  
  <p>New try with a flatMapConcat as suggested, but I still have an issue with the filename (doesn't compile). I don't know how to use the first element of the tuple as the filename of the sink ?</p>
  
  <pre><code>  val f = Source(1 to numberOfFiles)
      .map{ i =&gt;
        val fileName = UUID.randomUUID().toString
        println(fileName)
        fileName
      }
      .flatMapConcat { f =&gt;
        Source(1 to numberOfCustomers).map{ p =&gt;
          val rMsisdn = TestUtils.randomString(8)
          (f,List(1 to Random.nextInt(20)).map{ i=&gt;
            val rCdr= RandomCdr(rMsisdn)
            ByteString(s"${rCdr.msisdn};${rCdr.dateTime};${rCdr.peer};${rCdr.callType};${rCdr.way};${rCdr.duration}\n")
          }.fold(ByteString())(_ concat _))
        }
      }
      .runWith(FileIO.toPath(Paths.get(s"/home/reactive/data/$fileName")))
  </code></pre>