Search code examples
performancescalafor-comprehension

Performance of for-comprehension in scala


I've a question about the efficiency of for-comprehensions in scala.

This following code takes around 45 sec to run when perm is a list of around 550 elements

perm = some list
for{
   perm <- perms.withFilter(_.size > 0)
   wordList = somefunction(perm) //expensive operation, wordlist is a list of strings
   sentenceList = somefunction1(perm) //very expensive operation, sentenceList is a list of list of strings
   word <- wordList
   sentence <- sentenceList
} yield { word::sentence}

When I changed the following code into the following, it ran in 3 sec with the same perm list

perm = some list
for{
   perm <- perms.withFilter(_.size > 0)
   word <- somefunction(perm) //expensive operation
   sentence <- somefunction1(perm) //very expensive operation
} yield { word::sentence}

Does the difference in the performance has something to do with lazy evaluation in Scala?


Solution

  • Let's desugar both for-comprehensions:

    1.)

    perms.withFilter(_.size > 0).flatMap { perm =>
      val wordList = somefunction(perm) //expensive operation
      val sentenceList = somefunction1(perm) //very expensive operation
      wordList.flatMap { word =>
        sentenceList.map { sentence =>
          word::sentence
        }
      }
    }
    

    2.)

    perms.withFilter(_.size > 0).flatMap { perm =>
      somefunction(perm).flatMap { word =>
        somefunction1(perm).map { sentence =>
          word :: sentence
        }
      }
    }
    

    In the first case, both expensive functions will be executed every time. In the second case, when somefunction(perm) returns an empty result, somefunction1(perm) will never be executed.