简体   繁体   English

Java 8中的completableFuture是否可扩展到多个内核?

[英]Does completableFuture in Java 8 scale to multiple cores?

Lets say I have a single thread that calls bunch of methods that return completablefuture and say I add all of them to a list and in the end I do completablefutures.allof(list_size).join() . 让我说我有一个线程调用返回completablefuture的一堆方法,并说我将所有这些添加到列表中,最后我做了completablefutures.allof(list_size).join() Now does the futures in the list can scale to multiple cores? 现在列表中的期货可以扩展到多个核心吗? other words are the futures scheduled into multiple cores to take advantage of parallelism? 换句话说是将期货安排到多个核心以利用并行性?

CompletableFuture represents a task which is associated with some Executor . CompletableFuture表示与某个Executor关联的任务。 If you did not specify executor explicitly (for example, you used CompletableFuture.supplyAsync(Supplier) instead of CompletableFuture.supplyAsync(Supplier, Executor) ) , then common ForkJoinPool is used as executor. 如果未明确指定执行程序(例如,您使用CompletableFuture.supplyAsync(Supplier)而不是CompletableFuture.supplyAsync(Supplier, Executor) ,则使用常见的ForkJoinPool作为执行程序。 This pool could be obtained via ForkJoinPool.commonPool() and by default it creates as many threads as many hardware threads your system has (usually number of cores, double it if your cores support hyperthreading). 这个池可以通过ForkJoinPool.commonPool()获得,并且默认情况下它会创建与您的系统具有的许多硬件线程一样多的线程(通常是核心数,如果您的核支持超线程,则加倍)。 So in general, yes, if you use all defaults, then multiple cores will be used for your completable futures. 所以一般来说,是的,如果您使用所有默认值,那么多个核心将用于您的可完成期货。

CompletableFuture itself is not scheduled to a thread (or core). CompletableFuture本身未安排到线程(或核心)。 Tasks are. 任务是。 To achieve parallelism, you need to create multiple tasks. 要实现并行性,您需要创建多个任务。 If your methods which return CompletableFuture submit tasks like 如果您返回CompletableFuture的方法提交了类似的任务

return CompletableFuture.supplyAsync(this::calculate); return CompletableFuture.supplyAsync(this :: calculate);

then multiple tasks are started. 然后开始多个任务。 If they just create CompletableFuture like 如果他们只是创建CompletableFuture

return new CompletableFuture(); 返回新的CompletableFuture();

then no tasks are started and no parallelism present. 然后没有任务启动,也没有并行性存在。

CompletableFuture objects created by CompletableFuture{handle, thenCombine, thenCompose, thenApply} are not connected to parallel tasks, so parallelism is not increased. CompletableFuture {handle,thenCombine,thenCompose,thenApply}创建的CompletableFuture对象未连接到并行任务,因此并行性不会增加。

CompletableFuture objects created by CompletableFuture{handleAsync, thenCombineAsync, thenComposeAsync, thenApplyAsync} are connected to parallel tasks, but these tasks are executed strictly after the task corresponding to the this CompletableFuture object, so cannot increase parallelism. CompletableFuture创建的CompletableFuture对象{handleAsync,thenCombineAsync,thenComposeAsync,thenApplyAsync}连接到并行任务,但这些任务严格执行与this CompletableFuture对象对应的任务后,因此无法增加并行性。

Having a bunch of CompletableFuture s doesn't tell you anything about how they will be completed. 拥有一堆CompletableFuture并没有告诉你如何完成它们。

There are two kind of completions: 有两种完成方式:

  • Explicit, through cancel , complete , completeExceptionally , obtrudeException and obtrudeValue on an instance, or by obtainng a future with the completedFuture static method 显式,通过cancelcompletecompleteExceptionallyobtrudeExceptionobtrudeValue上的obtrudeExceptionobtrudeValue ,或者通过completedFuture静态方法获取未来

  • Implicit, through executing a provided function, whether it returns normally or exceptionally, or through the completion of a previous future 通过执行提供的函数隐式,无论是正常返回还是异常返回,还是通过完成前一个未来

    For instance: 例如:

    • exceptionally completes normally without running the provided function if the previous future completes normally exceptionally正常完成,如果没有以前的将来完成正常运行所提供的功能

    • Every other chaining method, except for handle and whenComplete and their *Async variations, complete exceptionally without running the provided function if the previous future, or any of the previous futures in the combining ( *Both* , *Combine* and *Either* ) methods, complete exceptionally 除了handlewhenComplete以及它们的*Async变体之外的所有其他链接方法,如果以前的未来或者组合中的任何前一个未来( *Both**Combine**Either* ),则不会运行提供的函数而异常完成方法,特别完整

    • Otherwise, the future completes when the provided function runs and completes either normally or exceptionally 否则,当提供的函数正常或异常运行并完成时,将来就会完成

If the futures you have were created without a function or they're not chained to another future, or in other words, if they don't have a function associated, then they will only complete explicitly, and as such it makes no sense to say if this kind of completable future runs , much less if they may use multiple threads. 如果您拥有的期货是在没有函数的情况下创建的,或者它们没有被链接到另一个未来,或者换句话说,如果它们没有关联的函数,那么它们只会明确地完成,因此它没有任何意义如果这种可完成的未来会运行 ,那么如果它们可以使用多个线程则更少。

On the other hand, if the futures have a function, it depends on how they were created: 另一方面,如果期货有一个函数,则取决于它们的创建方式:

  • If they're all independent and use the ForkJoinPool.commonPool() (or a cached thread pool or similar) as the executor, then they will probably run in parallel, possibly using as many active threads as the number of cores 如果它们都是独立的并使用ForkJoinPool.commonPool() (或缓存的线程池或类似的)作为执行程序,那么它们可能会并行运行,可能使用与核心数一样多的活动线程

  • If they all have a dependency on each other (except for one) or if the executor is single-threaded, then they'll run one at a time 如果它们彼此依赖(除了一个)或者执行程序是单线程的,那么它们将一次运行一个

  • Anything in between is valid, such as: 介于两者之间的任何内容都是有效的,例如:

    • some futures may depend on each other, or on some other internal future you have no knowledge of 一些期货可能相互依赖,或者在其他一些你不了解的内部未来

    • some futures may have been created with eg a fixed thread pool executor where you'll see a limited degree of concurrently running tasks 可能已经创建了一些期货,例如固定的线程池执行程序 ,您将看到有限程度的并发运行任务

Invoking join does not tell a future to start running, it just waits for it to complete. 调用join不会告诉将来开始运行,它只是等待它完成。

So, to finally answer your question: 所以,最后回答你的问题:

  • If the future has a function associated, then it may already be running, it may or may not run its function depending on how it was chained and the completion of the previous future, and it may never run if it doesn't have a function or if it was completed before it had a chance to run its function 如果未来有一个关联的函数,那么它可能已经在运行,它可能会或可能不会运行它的功能取决于它的链接方式和前一个未来的完成,如果它没有函数它可能永远不会运行或者如果在它有机会运行其功能之前完成了

  • The futures that are already running or that will run do so: 已经运行或将要运行的期货这样做:

    • On the provided executor when chained with the *Async methods or when created with the *Async static methods that take an executor 在使用*Async方法链接时或使用带有执行程序的*Async静态方法创建时提供的执行程序

    • On the ForkJoinPool.commonPool() when chained with the *Async methods or when created with the *Async static methods that don't take an executor 在使用*Async方法链接时或使用不带执行程序的*Async静态方法创建的ForkJoinPool.commonPool()

    • On the same thread as where the future they depend on is completed when chained without the *Async methods in case the future is not yet complete 在没有*Async方法链接的情况下完成与它们所依赖的未来相同的线程,以防未来尚未完成

    • On the current thread if the future they depend on is already completed when chained without the *Async methods 在当前线程上,如果它们依赖的未来在没有*Async方法的链接时已经完成


In my opinion, the explicit completion methods should have been segregated to a eg CompletionSource interface and have a eg CompletableFutureSource class that implements it and provides a future, much like .NET's relation between a TaskCompletionSource and its Task . 在我看来,显式完成方法应该被隔离到例如CompletionSource接口,并且有一个例如CompletableFutureSource类来实现它并提供未来,就像TaskCompletionSourceTask之间的.NET关系一样。

As things are now, most probably you can tamper with the completable futures you have by completing them in a way not originally intended. 就像现在的情况一样,很可能你可以用一种非原定的方式完成它们来篡改你所拥有的可完成的未来。 For this reason, you should not use a CompletableFuture after you expose it publicly; 因此,您不应在公开公开后使用CompletableFuture ; it's your API user's CompletableFuture from then on. 从那时起,它就是您的API用户的CompletableFuture

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM