when using Kotlin Coroutines a `suspend` function ...
# arrow
a
when using Kotlin Coroutines a
suspend
function should not use blocking operations. How is this in the context of arrow-fx and
IO
? Is this a requirement here too or is
suspend
only used as a marker to tag functions for having sideeffects?
a
I'd say the second one, as you wrap your suspend functions with IO, you are able to easily switch threads if that's something you need
not sure why is it like this in the kotlin coroutines tho, do you have more info about that?
a
as far as i understand multiple coroutines may be executed by a single thread, using a blocking operation in one coroutine would prevent this thread from executing the other coroutines. therefor one should use the non blocking suspending alternatives (e.g.
delay
instead of
sleep
)
a
ahh i see, thank you 🙂
r
You should try to avoid blocking operations in general but if you must you should use a dispatcher that is able to allocate more threads to fulfill them. The kind of dispatcher and whether the default dispatcher works is gonna depend on the kind of blocking op you are doing.
The default dispatcher uses work stealing and favors cpu bound ops over I/O blocking ops.
a
thanks. is that the correct way to use a custom dispatcher?
Copy code
IO.effect(IO.dispatchers().io()) {
  blockingFunctionHere()
}
a
afaik yes, you can even drop the
effect
and just call it like a constructor
Copy code
IO(IO.dispatchers().io()) {
  blockingFunctionHere()
}
r
You can also do:
Copy code
IO.fx {
  continueOn(IO.dispatchers().io())
  val result = !effect { blockingEffectHere() }
  continueOn(UIDispatcher)
  !effect { showResult(result) }
  continueOn(IO.dispatchers().default())
  !resumeBizAsUsualInForkJoinPool()    
}
while reading this gives the impression things could scape async because it looks like imperative code it all happens in the IO fx managed block and each one of those commands end up turning into flatMap chains underneath
You can also use fibers if you want finer control of when to fork/join to manually start and bind your processes. All other operations also use fibers underneath when required. This just gives you a more low level DSL. https://arrow-kt.io/docs/fx/async/#fibers like async/await
And if you need to get lower the Fx library includes concurrency primitives like Semaphore IORef and others that allow you to use concurrent/async synchronized mutable variables.
but that are still pure in the context of IO
a
thanks @raulraja @aballano!
👍 2