Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add runtime flag to enable / disable execution shift deferring #8854

Merged

Conversation

kyri-petrou
Copy link
Contributor

Related issue: #8368

Context

The current behaviour of the ZIO runtime is to defer execution context shifting until an async operation takes place. There is a fair bit of debate around this behaviour, with valid arguments from both sides.

The good

Reducing execution context shifting can improve performance, especially in situations where we might be constantly shifting in-and-out of the execution context.

for {
  a <- ZIO.succeedBlocking(10)
  b = a + 10
  c <- ZIO.succeedBlocking(foo(b))
} yield c

In the case below, execution context shifting deferral works well because after the first line is evaluated, we continue execution in the blocking threadpool, which means that when the 2nd ZIO.succeedBlocking occurs, we won't be shifting back execution.

Another valid usecase is the one below, where execution context shifting allows us the same thread to execute the _ + 1 computation, before it reaches the end of the async boundary.

ZIO.foreachPar(1 to 100)(i => ZIO.succeedBlocking(foo(i)).map(_ + 1))

The bad

The most common use-case for shifting execution context is to perform blocking IO. In many cases, it is very likely to perform some/much CPU work to process the data obtained via IO. Since ZIO's blocking threadpool is unbounded, this means we could end up running CPU-bound workflows, which is.. very bad.

One example where this happens is in zio-query. What might not be immediately obvious in that code-block is that dataSources are almost definitely going to perform some IO, very often blocking IO. Following the execution of the datasource, we need to do some moderately expensive CPU such as creating HashMaps, fulfilling promises, etc.

PR changes

Currently, the only way to disable this behaviour is to override the default executor. However, this is just a side effect rather than the intended behaviour, and that might change at some point in the future.

Instead of taking sides on this argument, I think a better approach is to give users the option to control this behaviour explicitly via a RuntimeFlag (enabled by default to maintain the same behaviour as before). This also unlocks the potential for power users to enable/disable this behaviour in specific regions

PS: Please provide some feedback/alternatives for the naming of the flag. I think we can do better!

@ghostdogpr
Copy link
Member

That flag sounds like it's going to defer the shifting even if you have an overriden executor. How about the inverse of this? Something like InstantShiftBack, off by default?

@jdegoes
Copy link
Member

jdegoes commented May 14, 2024

EagerShiftBack?

@jdegoes
Copy link
Member

jdegoes commented May 14, 2024

EagerBackshift?

@kyri-petrou
Copy link
Contributor Author

Sorry this took me a while. Thanks for the recommendations, I updated the name of the flag to EagerShiftBack and disabled it by default

@kyri-petrou kyri-petrou merged commit 9763fa6 into zio:series/2.x May 21, 2024
21 checks passed
@kyri-petrou kyri-petrou deleted the execution-shift-deferring-flag branch May 21, 2024 06:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants