Cloud tech Cloud tech - 2 months ago 18
Scala Question

scalaz.concurrent.Task repeatEval only evaluate Task.now and Task.async once

I am learning scalaz stream at the moment, I am confused why repeatEval only evaluate Task.async once.

val result = Process
.repeatEval(Task.async[Unit](t => {
val result = scala.io.Source.fromURL("http://someUrl").mkString
println(".......")
println(result)
}))

result.runLog.run //only print once


However, if I change Task.async to Task.delay. It evaluates the function infinitely. I dont know why is that

val result = Process
.repeatEval(Task.delay({
val result = scala.io.Source.fromURL("http://someUrl").mkString
println(".......")
println(result)
}))

result.runLog.run //print infinitely


Many thanks in advance

Answer

As I mention in my answer to your recent question about Task, Task.async takes a function that registers callbacks—not some code that should be executed asynchronously. In the case of the other question, you actually want Task.async, since you're interoperating with a callback-based API.

Here it seems like you probably want Task.apply, not Task.delay. The two look similar, but delay simply suspends the computation—it doesn't use an ExecutorService to run it in a separate thread. You can see this in the following example:

import scalaz._, Scalaz._, concurrent._

val delayTask = Task.delay(Thread.sleep(5000))
val applyTask = Task(Thread.sleep(5000))

Nondeterminism[Task].both(delayTask, delayTask).run
Nondeterminism[Task].both(applyTask, applyTask).run

The delayTask version will take longer.