Reputation: 12804
In Scala, as explained in the PR that introduced it, parasitic
allows to steal
execution time from other threads by having its
Runnable
s run on theThread
which callsexecute
and then yielding back control to the caller after all itsRunnable
s have been executed.
It appears to be a neat trick to avoid context switches when:
Future
coming from an actually long running operation, orExecutionContext
for a Future
but you but you would like to make sure the operation continues on that same thread, without introducing a different threadpoolThe PR that originally introduced parasitic
further explains that
When using
parasitic
with abstractions such asFuture
it will in many cases be non-deterministic as to whichThread
will be executing the logic, as it depends on when/if thatFuture
is completed.
This concept is also repeated in the official Scala documentation in the paragraphs about Synchronous Execution Contexts:
One might be tempted to have an ExecutionContext that runs computations within the current thread:
val currentThreadExecutionContext = ExecutionContext.fromExecutor( new Executor { // Do not do this! def execute(runnable: Runnable) { runnable.run() } })
This should be avoided as it introduces non-determinism in the execution of your future.
Future { doSomething }(ExecutionContext.global).map { doSomethingElse }(currentThreadExecutionContext)
The
doSomethingElse
call might either execute indoSomething
’s thread or in the main thread, and therefore be either asynchronous or synchronous. As explained here a callback should not be both.
I have a couple of doubts:
parasitic
different from the synchronous execution context in the Scala documentation?parasitic
it sounds like if doSomething
completes very quickly it may return control to the main thread and you may end up actually not running doSomethingElse
on a global
thread but on the main one. That's what I could make of it, but I would like to confirm.Future
abstraction (e.g. IO
in Cats) could make this more easy and reliable, but I'd like to understand if this is possible at all using the Future
from the standard library.Upvotes: 3
Views: 564
Reputation: 26597
parasitic
has an upper bound on stack recursion, to try to mitigate the risk of StackOverflowErrors due to nested submissions, and can instead defer Runnables to a queue.I find that it is easier to think about Futures as read-handles for values that may or may not exist at a specific point in time. That nicely untangles the notion of Threads from the picture, and now it is rather about: When a value is available, I want to do X—and here is the ExecutionContext that will do X.
Upvotes: 4