-
-
Notifications
You must be signed in to change notification settings - Fork 639
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
Execute Future operations on the same Thread by default #1530
Comments
The Future core (FutureImpl) is small and well organized. By changing a single line we managed to execute all actions on the same Future Thread: private void perform(Consumer<? super Try<T>> action) {
- Try.run(() -> executorService.execute(() -> action.accept(value.get())));
+ Try.run(() -> value.forEach(action));
} But this is only for testing purposes and not the solution for the problem. We still need to execute the actions by an ExecutorService. It has to be a new single thread ExecutorService (singleton) by default with the option to exchange that: final Future<T> future = Future.of(someExecutor, () -> computation());
// these use the same thread of future to process result
future.onComplete(Handler::processResult);
future.map(mapper);
...
// these use a new thread provided by fooExecutor to process result
future.onComplete(fooExecutor, Handler::processResult);
future.map(fooExecutor, mapper);
... |
TODO: Re-enable |
This issue should solve the following problem (tests by @mattjtodd): BlockingQueue<Runnable> queue = new SynchronousQueue<>();
ExecutorService service = new ThreadPoolExecutor(1, 1 , 0L, TimeUnit.MILLISECONDS, queue);
Future
.of(service, () -> { Thread.sleep(100); return true; })
.onComplete(System.out::println);
Thread.sleep(2000);
service.shutdown(); Which results in the CompletableFuture
.supplyAsync(() -> Try
.run(() -> TimeUnit.MILLISECONDS.sleep(100))
.map(result -> true)
.getOrElseThrow(() -> new IllegalStateException()), service)
.whenCompleteAsync((result, thrown) -> {
System.out.println(result + " : " + thrown);
}, service); It would be good to have the expression run on the task thread by default and have variants to supply an In Javaslang this would look like this: Future.of(fooExecutor, this::computation) // executes the async computation using fooExecutor
.on(barExecutor) // this line is optional, it will execute all supsequent operations using barExecutor
.map(...) // this will execute the map operation on the same task the future currently runs on
.map(bazExecutor, ...) // this will execute (only) this map operation on a task created by bazExecutor
... I created a new issue for the |
|
UPDATE: We can't do execute all action on one thread. That would be inefficient. In general, the actions are executed in parallel.
However, the issues mentioned below (currently @ignored in our unit tests) should be solved. Therefore I will leave this ticket open.
OBSOLETE:
It is interesting that Scala's Future does not reuse threads. Spawning new threads is a waste of resources - more context switches and parallel threads than necessary. Some are even completed and wait to be returned to the pool. This makes it intransparent for the call-site/user how resources are managed. The risk of a deadlock increases when having bounded pools.
I see only bebefits in reusing threads that already idle because the Future already completed on subsequent operations.
It is common to add an onComplete handler or an onSuccess and an onFailure handler. We rarely see adding many complete handlers. This means that only one handler is executed when the underlying Future is complete and does idle. In other words the theead can be reused.
If another behavior is needed, an ExecutorService should be explicitly specified when calling an operation or registering a handler. We will provide additional methods for that.
This change of behavior is expected to be binary backward compatible.
The text was updated successfully, but these errors were encountered: