[concurrency-interest] CompletableFuture in Java 8
dl at cs.oswego.edu
Sat Dec 13 11:51:56 EST 2014
On 12/08/2014 11:35 AM, Josh Humphries wrote:
> You've already mentioned that you'd like to see ExecutorService retired.
> It definitely has plenty of sharp corners. But I'll hold judgement on
> whether or not its use should be retired for when I see its replacement
> (sorry, FJP, you're not it.)
Suggestions are always welcome.
In principle, it is always possible to build a custom scheduler
that will work better than any possible general-purpose j.u.c Executor
for a known collection of activities with known dependencies, But
in practice, the combination of centralized ThreadPoolExecutor and
decentralized ForkJoinPool have evolved to cover enough of the
territory that we focus on improving rather than replacing.
A few further improvements of each might occur relatively soon.
Plus, probably less soon, better ways to address the memory locality,
contention, and affinity issues common to all multicore schedulers.
> I'm actually toying with something that might be kinda-sorta like this now. It's
> like an ExecutorService, but you give each submission a "key" (think Actor or
> Listener) so submissions from outside of the pool (like non-FJ code) can try to
> pin the task to "the right thread" instead of a random thread (and hopefully get
> better L1 cache hit rate). At the same time, it also employs work-stealing to
> improve throughput and fairness.
This is what FJ does, but the "key" is a hidden thread-local hash-based
queue index that changes only if contended with another. This avoids
unbounded growth in worker threads, at the expense of residual
low likelihood of continued contention. Empirically, this seems
to be a good tradeoff.
> One difference in what I'm trying to do is that it is specifically for
> sequential delivery of events to listeners (and could be used for executing
> operations on behalf of an actor in something like Akka).
If a later task B cannot start before an earlier task A completes,
then sequential execution would be a better approach than treating
as async with B dependent on completion of (i.e., joining) A.
In other words, (A; B) should be batched as a single task.
It seems that this is what your queue-stealing is in effect
doing. We might be able to generalize this into more
flexible adaptive support for batching, with possible dependencies
across batches. (This was the subject of some experiments we did
on work-stealing-based graph algorithms a few years ago that didn't
make it into any FJ release, but there are now several reasons to
Anyway, it may well be the case that you have enough extra
context and constraints to make a specialized Executor worthwhile,
but we are also always trying to improve the general-purpose ones.
More information about the Concurrency-interest