Temporal coupling in Fibers and Fibers vs State Machines.
Ron Pressler
ron.pressler at oracle.com
Thu Feb 20 14:21:21 UTC 2020
Not necessarily. It depends on the implementation of both the future and the
scheduler. For example, Future.get could itself call back into the scheduler
to run tasks while waiting. I believe this is what CompletableFuture does
on a ForkJoinPool. In any event, whether *any* instruction — not just
Future.get — is ever completed is entirely dependent on scheduler
implementation details.
It is true that Loom allows a user to provide their own scheduler for j.l.Threads,
something that has so far been left for the operating system (although
users could still write implementations of j.u.c.Future), but I think that the
great care required in writing a scheduler is the responsibility of the
implementer of the scheduler (and of the Future), rather than that of the
abstraction, that is meant to hide such scheduling details. Authors of such
important, low-level constructs should document their proper use.
- Ron
On 20 February 2020 at 12:41:19, Alex Otenko (oleksandr.otenko at gmail.com(mailto:oleksandr.otenko at gmail.com)) wrote:
> Not just self-reference.
>
> When talking about Future.get, one should not say "it blocks just one Thread [we can afford it]". Instead, say "it blocks one Thread at a time". It becomes obvious that such use can block an arbitrary number of threads, so thread pools with upper bound on size will eventually deadlock.
>
>
> Alex
> On Thu, 20 Feb 2020, 12:34 Ron Pressler, wrote:
> > > My point was more that the safe actions on a CompletableFuture are different depending on the underlying ExecutorService
> >
> > Almost anything you do in a concurrent context depends on the scheduler. Whether
> > blocking on *anything* will ever complete, or equivalently, whether a task
> > submitted for execution will ever run, depends on the fairness of the scheduler.
> >
> > In fact, on operating systems that do time-slice-based preemption, any piece
> > of code can stop running at any time and never continue. So when we write a;b
> > and assume that b will run if a terminates, we rely on an implicit assumption
> > that the scheduler is fair.
> >
> > > CompletableFuture#join or Future#get is only safe if you do that join from a thread in a different pool than the one the Future runs on.
> >
> > I am not familiar with this rule. I believe that CompletableFuture.join,
> > when running on FJP, will help execute tasks. I believe you are referring
> > to the possibility of a self-deadlock, but this, too, has implicit
> > assumptions. Depending on the implementation of the future, as well as of the
> > scheduler, any blocking operation could potentially never terminate.
> >
> > - Ron
> >
> >
> > On 20 February 2020 at 01:24:30, Thomas May (tmay at clearwateranalytics.com(mailto:tmay at clearwateranalytics.com)(mailto:tmay at clearwateranalytics.com)) wrote:
> >
> > > My point was more that the safe actions on a CompletableFuture are different depending on the underlying ExecutorService, particular with Loom.
> > >
> > > CompletableFuture#join or Future#get is only safe if you do that join from a thread in a different pool than the one the Future runs on.
> > >
> > > It often becomes a style rule to simply say "Never call CompletableFuture#join". That calculus changes significantly with Loom.
> > > Join is suddenly perfectly fine (if not preferred!) over more complex then* methods. It's arguably a lot more readable.
> > >
> > > If I have some method which does a lot of future wrangling, how I implement it (and even the return type!) will change drastically if
> > > I think those futures are on an UnboundedExecutorService of virtual threads vs a fixed thread pool. (The latter being a bunch of then* functions returning a CompletableFuture).
> > >
> > > This is where it might help to expose some of that information at the type system. It could be nice if UnboundedExecutorService returned a UnboundedFuture or... whatever (I'm terrible at names).
> > >
> > > IDK, though, maybe it's enough to just inject an UnboundedExecutorService where the futures are made.
> > > I mean, ultimately, we have things like "ManagedBlocker" which only really operates if the pool it runs on is a FJP. That’s somewhat the same issue.
> > >
> > > -----Original Message-----
> > > From: Ron Pressler
> > > Sent: Wednesday, February 19, 2020 2:20 PM
> > > To: Thomas May ; loom-dev at openjdk.java.net(mailto:loom-dev at openjdk.java.net)
> > > Subject: Re: Temporal coupling in Fibers and Fibers vs State Machines.
> > >
> > > > it means you have to start caring at a function level "Is this running on a fiber pool or a regular pool”.
> > >
> > > I don’t think it does.
> > >
> > > Every abstraction, pretty much by definition, hides some implementation details.
> > > Java’s Map and List interfaces hide the cost of their operations; parallel streams hide the number of processors, and threads hide the implementation of a scheduler.
> > >
> > > If you’re writing a real-time application you might care a great deal about the implementation of the scheduler — whether it handles priority inversion, whether it works in a strict round-robin fashion etc.. Other times, you might care less.
> > > But guess what? Reactive frameworks *also* hide the implementation of the scheduler.
> > > IIRC, the Reactive Streams specification allows the scheduler to schedule all operations onto a single thread, and make all operations blocking. So you need to care about the implementation of the scheduler to the same extent, whether you’re writing synchronous or asynchronous code. Just as you pick a scheduler for your asynchronous code, you can pick one for your synchronous code.
> > >
> > > So I don’t see how threads make caring about scheduling more or less important. They just offer a different way of expressing the same computation, a way that happens to be more in line with how the Java platform — that’s largely organised around the thread abstraction — is designed.
> > >
> > > - Ron
> > >
> > >
> > > On 19 February 2020 at 20:36:05, Thomas May (tmay at clearwateranalytics.com(mailto:tmay at clearwateranalytics.com)(mailto:tmay at clearwateranalytics.com)) wrote:
> > >
> > > > > Martin's concerns are, if by composition he means what I think he
> > > > > means, if
> > > > you could set up pieces of computation and functionality and combine
> > > > them into larger components. If so, these components can have state
> > > > and those state could change in response to stimuli from other
> > > > components. Reactive is one of such approach that has individual
> > > > pieces - operators chained up on a dataflow have internal state
> > > > tracking when and how their peers can send data and commands to each
> > > > other. Loom's, and Kotlin's Coroutines instead say you compose via the
> > > > source code itself, by writing larger and larger methods encompassing
> > > > a lot of imperative operations. If you have such a method, but for
> > > > some uses need some retry code, you may be out of luck and have to
> > > > code yet another set of methods to include that functionality.
> > > >
> > > > I believe the concerns are more that things like "CompletableFutures"
> > > > are hard to intuitively compose correctly.
> > > >
> > > > For example, think of a graph of Futures. Now imagine you want to
> > > > conditionally traverse the graph based on node the values returned by each future and cancel the rest based on some condition.
> > > >
> > > > With CompletableFutures and traditional threads, that's really
> > > > difficult without introducing a lot of blocking on some thread. In
> > > > fact, it's pretty much impossible using the composition methods available. You are forced to call `.join()`. This is isn't so bad with loom backed completable future but it is a killer for the standard FJP.
> > > >
> > > > On the flip side, async/await syntax handles this sort of thing pretty
> > > > much right out of the box. The awaits all allow the current thread to
> > > > go do something else useful and, as a bonus, are pretty easy to read. The downside is the colored function problem.
> > > >
> > > > I believe that is where the composition statement comes into play.
> > > > Futures and promises are hard to compose correctly. They end up
> > > > looking ugly and hard to read. Loom helps here, but ultimately, it means you have to start caring at a function level "Is this running on a fiber pool or a regular pool".
> > > > If the answer is a regular pool, you run serious risks calling .join() if your code is also executing within the same pool.
> > > >
> > > > Just my two cents.
> > > >
> > > > I still like the loom approach simply because it eliminates the
> > > > colored function problem without adding extra cognitive burden.
> > > >
> > > > ________________________________
> > > >
> > > > NOTICE: This e-mail message, together with any attachments, contains information of Clearwater Analytics and/or its affiliates that may be confidential, proprietary copyrighted and/or legally privileged, and is intended solely for the use of the individual or entity named on this message. If you are not the intended recipient, and have received this message in error, please immediately delete it. The information we provide is from sources Clearwater Analytics considers reliable, but Clearwater Analytics provides no warranties regarding the accuracy of the information. Further, nothing in the email should be construed as legal, financial, or tax advice, and any questions regarding the intended recipient's individual circumstances should be addressed to that recipient's lawyer and/or accountant.
> > > >
> > > > Clearwater Analytics, 777 W. Main St, Boise, ID 83702 If you prefer
> > > > not to receive emails from Clearwater Analytics you may unsubscribe.
> > >
> > >
> > > ________________________________
> > >
> > > NOTICE: This e-mail message, together with any attachments, contains information of Clearwater Analytics and/or its affiliates that may be confidential, proprietary copyrighted and/or legally privileged, and is intended solely for the use of the individual or entity named on this message. If you are not the intended recipient, and have received this message in error, please immediately delete it. The information we provide is from sources Clearwater Analytics considers reliable, but Clearwater Analytics provides no warranties regarding the accuracy of the information. Further, nothing in the email should be construed as legal, financial, or tax advice, and any questions regarding the intended recipient’s individual circumstances should be addressed to that recipient’s lawyer and/or accountant.
> > >
> > > Clearwater Analytics, 777 W. Main St, Boise, ID 83702
> > > If you prefer not to receive emails from Clearwater Analytics you may unsubscribe.
> >
More information about the loom-dev
mailing list