[concurrency-interest] We need to add blocking methods to CompletionStage!
Gregg Wonderly
gergg at cox.net
Wed Sep 28 15:05:35 UTC 2016
The completely less thread consuming alternative is call backs. VMS used/uses Asynchronous System Traps (ASTs) for everything in the 1980s. It was a very performant and friendly way to allow small software modules to be written to do one thing and used as the call back for asynchronous system behaviors. I wrote several symbionts which did serial connection scripting for connecting to printers remotely, process management for process reuse on PMDF to speed up mail flow through the queue, and other things interactive with the kernel to alter process priorities to provide longer term scheduling on a heavily loaded 750. It was like heaven to have such a small amount of code (lots of functions, some global data). I am just suggesting that this kind of thing was a major part of more than one programming environment.
Having 100’s of threads blocked on various locks adds considerably to the overhead of scheduling but also complicates cache use and burdens the developer with looping and waiting in ways that increase bugs in code that should not exist. I really feel that the kind of thing that CompletionStage provides to the developer is something that should of been more prevalent from the start. It inverts programatic logic in some cases, but call backs really are the best way to react to asynchronous eventing in software.
Gregg Wonderly
> On Sep 21, 2016, at 4:25 PM, Benjamin Manes <ben.manes at gmail.com> wrote:
>
> My limited understanding is that the original API was only CompletableFuture and that CompletionStage introduced as a compromise. It did not appear to be an attempt to strictly follow an interface-implementation separation, e.g. collections. As you said #toCompletableFuture() may throw an UOE, which means some use-cases can't rely on CompletionState which limits its usefulness. In my case that would be an AsyncLoadingCache with a synchronous LoadingCache view. I think having to code that the resulting implementation would be worse if it called toCompletableFuture, caught the exception, and then adapted as you said.
>
> When the new future class was introduced it was stated,
>
> "In other words, we (j.u.c) are not now in a position to dictate a common interface for all SettableFuture, FutureValue, Promise, ListenableFuture, etc like APIs. And as we've seen, different audiences want/need different subsets of this API exposed as interfaces for their usages, and are in any case unlikely to want change all their existing interfaces. However, what we can do is provide a common underlying implementation that is as fast, scalable, space-conserving, carefully-specified, and reliable as possible. It should then be easy and attractive for others creating or reworking higher-level APIs to relay all functionality to the CompletableFuture implementation." - Doug Lea, '12
>
> I've gradually come to terms using CF as part of an API and haven't experienced a downside yet.
>
> On Wed, Sep 21, 2016 at 1:43 PM, Martin Buchholz <martinrb at google.com <mailto:martinrb at google.com>> wrote:
> (Sorry to re-open this discussion)
>
> The separation of a read-only CompletionStage from CompletableFuture is great. I'm a fan of the scala style Promise/Future split as described in http://docs.scala-lang.org/overviews/core/futures.html <http://docs.scala-lang.org/overviews/core/futures.html>, but: we need to re-add (safe, read-only) blocking methods like join. Java is not Node.js, where there are no threads but there is a universal event loop. Java programmers are used to Future, where the *only* way to use a future's value is to block waiting for it. The existing CompletionStage methods are a better scaling alternative to blocking all the time, but blocking is almost always eventually necessary in Java. For example, junit test methods that start any asynchronous computation need to block until the computation is done, before returning.
>
> As Viktor has pointed out, users can always implement blocking themselves by writing
>
> static <T> CompletableFuture<T> toCompletableFuture(CompletionStage<T> stage) {
> CompletableFuture<T> f = new CompletableFuture<>();
> stage.handle((T t, Throwable ex) -> {
> if (ex != null) f.completeExceptionally(ex);
> else f.complete(t);
> return null;
> });
> return f;
> }
>
> static <T> T join(CompletionStage<T> stage) {
> return toCompletableFuture(stage).join();
> }
>
> but unlike Viktor, I think it's unreasonable to not provide this for users (especially when we can do so more efficiently). What is happening instead is API providers not using CompletionStage as return values in public APIs because of the lack of convenient blocking, and instead returning CompletableFuture, which is a tragic software engineering failure.
>
> Re-adding join is easy. We discourage CompletionStage.toCompletableFuture from throwing UnsupportedOperationException, and implement join as:
>
> public default T join() { return toCompletableFuture().join(); }
>
> There is a risk of multiple-inheritance conflict with Future if we add e.g. isDone(), but there are no current plans to turn those Future methods into default methods, and even if we did in some future release, it would be only a source, not binary incompatibility, so far less serious.
>
> _______________________________________________
> Concurrency-interest mailing list
> Concurrency-interest at cs.oswego.edu <mailto:Concurrency-interest at cs.oswego.edu>
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest <http://cs.oswego.edu/mailman/listinfo/concurrency-interest>
>
>
> _______________________________________________
> Concurrency-interest mailing list
> Concurrency-interest at cs.oswego.edu
> http://cs.oswego.edu/mailman/listinfo/concurrency-interest
More information about the core-libs-dev
mailing list