-
Notifications
You must be signed in to change notification settings - Fork 1k
Clear up blocking _in_ a future vs blocking _on_ a future. #303
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
Conversation
this is an edit to SIP-14. could one or more of the SIP's authors review it? @phaller @axel22 @heathermiller @viktorklang @viktorklang @rkuhn @vjovanov |
## Blocking | ||
|
||
### in a Future |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please put a capital I
in In
here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would maybe write Blocking inside a future
.
Thanks a lot for your contribution and effort to clear this up! LGTM overall, please address the few details I commented. Btw, there is another futures doc where this should be added: |
@axel22 sorry, I was confused and managed to confuse you as well. this text derives from SIP-14, but it is not the SIP itself. the PR does in fact target the right page. |
@SethTisue even better, then, less work for the @backuitist ! |
|
||
As seen with the global `ExecutionContext`, it is possible to notify an `ExecutionContext` of a blocking call with the `blocking` construct. | ||
The implementation is however at the complete discretion of the `ExecutionContext`. While some `ExecutionContext` such as `ExecutionContext.global` | ||
implement `blocking` by means of a `ManagedBlocker`, some just do nothing: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps be clear why this is the case:
"some will do nothing, like Executors.newFixedThreadPool, as shown below:"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This paragraph is about ExecutionContext
and Executors.newFixedThreadPool
isn't one. You're talking about ExecutionContext.fromExecutor(Executors.newFixedThreadPool(x))
which in this sentence is overkill IMO.
What I could add though, is a comment in the code below:
// an ExecutionContext not aware of `blocking`
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could put that long expression into a separate line - like this:
Some execution contexts, such as the fixed thread pool:
... long expression ....
will do nothing, as shown in the following:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a bit redundant IMO but if you think that helps I'll add it.
898a8bf
to
4f768e0
Compare
@viktorklang ready to merge? |
implicit val ec = ExecutionContext.fromExecutor( | ||
Executors.newFixedThreadPool(4)) | ||
Future { | ||
// here blocking serves only for documentation purpose |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rereading the PR,
I think it is important to let the reader know that generally speaking: code using an ExecutionContext should not know implementation details regarding the ExecutionContext, and therefore any code that invokes blocking
does so to let the ExecutionContext deal with the situation in the best way it knows how to. I.e. it does not serve as documentation purpose. (If the readers think that it is somehow optional and only serves as documentation, then it's not really going to be used.)
Does that line of thinking make sense?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi Viktor,
I was actually quoting you when I wrote that blocking
serves for documentation purpose: https://groups.google.com/d/msg/scala-user/LKiVD2PGvew/CWufs2Z8K4UJ
If I use
ExecutionContext.fromExecutor(Executor)
the blocking construct will be made useless.It's not useless. not only can you install your own BlockContext but it serves as "documentation" so that if someone changes the EC implementation, your code can be made to run better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi Bruno,
Yes, in the case that the implementation behind the EC (or the currently installed BlockContext to be more precise) does not do anything, it is "effectively" documentation, but given that the EC typically is passed in, it may not be like that for all invocations.
My reservation is against making it sound like it is something that only serves documentation purposes, even if the EC implementation is known, because if the implementation changes in the future, it will be hard to track the blocking if that wasn't added when the code was written.
Does that make sense? :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't really changed my point of view on this matter since last year. IMO if you want to block you don't do it through a blocking
call but rather you'd use an EC that has been designed for that, such as a TPE with a large pool.
if the implementation changes in the future
Do you really believe that we'll see in the (foreseeable) future an EC implementation for TPE that can leverage blocking
?
In the mean time, this feature is dangerous and the least you can do is warn your users. I believe this PR addresses that perfectly.
Maybe @axel22 or @SethTisue could have a word on it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have a very strong opinion. Maybe we can omit the line which says that it's for documentation, and just say that it informs the EC so that it can optionally adjust its parallelism.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, the library should not instantiate its own EC, but that's not what I said. Libraries needing a blocking EC can merely declare it as a dependency, and if you want to leverage implicits you can do something along those lines:
[...]
As a matter of fact I believe that, as a general rule, implicit parameters are fine as long as they have a very specific meaning. blocking feels like a hack to work around the fact that we only have one kind of ExecutionContext, not 2.
But that's just my opinion, and for now I'm just suggesting that we make it clear that blocking might not work as expected under certain conditions.
I can understand that argument, I think we discussed having multiple ones initially but came to the conclusion that it was disruptive enough to have the ripple-effect of having to add (implicit ec: ExecutionContext)
up the call chain as soon as something async needed to be done down the call chain. Adding a new dimension where one also needed to add yet another implicit as soon as blocking was involved would have serious impact on binary and source compatibility. (Imagine having to add a blocking call, now all your signatures would change, so people would just do unmanaged blocking instead, which would mean that they'd block on the provided EC, without any means of parrying for it).
My long-standing plan has been to create a thread pool that would work well for both CPU-bound work á la FJP but also blocking work á la TPE, transitioning workers between those modes based on blocking
/BlockContext
. What would be fantastic about that is that code that uses blocking
would simply work with the new EC without any modification.
I took a quick look. That's nice, but that's not yet in the scala-library and, as far as I understand, that only works if you create your TPE-based EC through your ThreadPoolConfig. If someone has a TPE at hand (provided by some other code) and wants to wrap it in an EC through fromExecutor then you're stuck.
Of course, it is not a virus that infects other's object instances :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My long-standing plan has been to create a thread pool that would work well for both CPU-bound work á la FJP but also blocking work á la TPE, transitioning workers between those modes based on blocking/BlockContext. What would be fantastic about that is that code that uses blocking would simply work with the new EC without any modification.
That's fair, but how about leaving this PR as it is now and updating it once the scala-library gets upgraded with your silver bullet EC?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@backuitist Nice try ;)
Since there is nothing that prevents, nor precludes that such a threadpool already exists and is used in production daily, I think this PR should be amended such that it is clear that the primary thing about blocking
is about demarcation rather than mere documentation :)
Everything else looks fantastic, it's a great contribution!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@viktorklang I surrender! ;)
How should we go about it? Do like @axel22 proposal? Would that work for you to remove that line?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Deal, I think @axel22's proposal is a good middle ground.
@SethTisue Thanks for the ping. I have one final comment (added). |
4f768e0
to
e61c7f5
Compare
Clear up blocking _in_ a future vs blocking _on_ a future.
thank you @backuitist for the submission and for getting it past our tough pack of reviewers :-) |
No description provided.