scalaz / ioeffect

An effect monad for Scalaz 7.2
Other
55 stars 9 forks source link

Help me understand racing :) #29

Closed NeQuissimus closed 6 years ago

NeQuissimus commented 6 years ago

OK, so here I thought race was straight-forward. Clearly I am doing something wrong...

import $ivy.`org.scalaz::scalaz-ioeffect:2.1.0`, scalaz._, ioeffect._, Scalaz._, scala.concurrent.duration._

object App extends SafeApp {
    type Error = Exception

    def run(args: List[String]): IO[Error, Unit] = {
      val io1 = IO.sleep[Error](10.seconds).fork[Error]
      val io2 = IO.point[Error, Unit]{ println("Hello"); Thread.sleep(500L) }.forever[Unit].fork[Error]
      io1.race(io2).toUnit
}

App.main(Array.empty)

I was under the impression the two IO would race each other and once the first one finishes (clearly the sleeper, since the other one is a forever guy), the slower one is interrupted and will never be heard of again. In the above code io2 is completely unfazed by the race and will keep on running forever. Can an IO.forever not be interrupted?

Anyways, I changed things around a bit, thinking maybe one of the fibres is not allowed to be forked, and now I have this:

import $ivy.`org.scalaz::scalaz-ioeffect:2.1.0`, scalaz._, ioeffect._, Scalaz._, scala.concurrent.duration._

object App extends SafeApp {
  type Error = Exception

  def run(args: List[String]): IO[Error, Unit] = {
    val io1: IO[Error, Unit] = IO.sleep[Error](10.seconds).fork[Error].toUnit
    val io2: IO[Error, Unit] = IO.point(println("Hello")).forever[Unit]
    io1.race(io2)
  }
}

App.main(Array.empty)

a) The race lasts maybe 1 second, not 10, not forever b) Sometimes I get a bunch of prints but usually only one


Here is essentially what I need (maybe there is a significantly better way to do this):

ktonga commented 6 years ago

Maybe in this very case it is not the reason, but in general i'd not recommend to try concurrent-ish stuff on the REPL, I see you are using Ammonite, dunno if it is the same as with sbt console but I always get better (expected) behavior when writing a little app in a scala file and using sbt run

jdegoes commented 6 years ago

Thus io2 will be terminated very quickly, after some non-deterministic number of println.

What I think you want is simple X.race(Y), not X.race(Y.fork).

NeQuissimus commented 6 years ago

Oh! I thought I had to fork at least one of them. This makes sense...

jdegoes commented 6 years ago

@NeQuissimus Let the types be your guide! 😉 If they allow to do something, then it's a valid operation (or if it's not, then I have some work to do).

NeQuissimus commented 6 years ago

@jdegoes .toUnit should have probably been enough of a hint that I need to rethink what I am doing :D