cats-effect
cats-effect copied to clipboard
The `factorial` sample code in the Thread Model documentation is a little misleading
Page: https://typelevel.org/cats-effect/docs/thread-model#fibers Documentation parts:
It is important to note that this is cooperative multi-tasking (as opposed to pre-emptive) so it is the responsibility of a fiber to yield control of the CPU by suspending its runloop periodically. In practice this is rarely an issue as fibers automatically yield at asynchronous boundaries (eg I/O) but it does means that it is actually possible for a fiber to take control of a CPU core and never give it back if it executes a tight CPU-bound loop like
def factorial(n: BigInt): IO[BigInt] = n match {
case 0 => IO.pure(1)
case n => factorial(n-1).flatMap {
m => IO.pure(m * n)
}
}
factorial(10000).unsafeRunSync()
If you have such a loop then you can insert a fairness boundary via
IO.shift(CE2 but has other potential side-effects) orIO.cede(CE3), which will give another fiber an opportunity to run on the thread.
The documentation says the above code won't yield control of the CPU which is not true.
In CE3 with the above code sample, there is no need to insert the fairness boundary with IO.cede because the CE3 will insert an IO.cede every fixed number of iterations of the runloop mentioned in the later documentation.
Maybe it is better to use another example which actually needs to use IO.cede or add a note to let the users know the CE3 will add the fairness boundary in the example code.