8

假设我有一个线程调用一堆返回 completablefuture 的方法,并说我将它们全部添加到一个列表中,最后我做了completablefutures.allof(list_size).join()。现在列表中的未来是否可以扩展到多个核心?换句话说,未来是否安排到多个内核中以利用并行性?

4

3 回答 3

18

CompletableFuture表示与 some 相关联的任务Executor。如果您没有明确指定 executor(例如,您使用CompletableFuture.supplyAsync(Supplier)而不是CompletableFuture.supplyAsync(Supplier, Executor),那么 commonForkJoinPool将用作 executor。这个池可以通过获得ForkJoinPool.commonPool(),默认情况下,它会创建与系统拥有的硬件线程一样多的线程(通常是内核数量,如果您的内核支持超线程,则将其加倍)。所以一般来说,是的,如果你使用所有默认值,那么多个核心将用于你的可完成期货。

于 2016-06-02T03:40:59.123 回答
2

拥有一堆CompletableFutures 并不能告诉您它们将如何完成。

有两种完成方式:

  • 显式,通过cancel, complete, completeExceptionally, obtrudeExceptionand在实例上,或通过使用静态方法obtrudeValue获得未来completedFuture

  • 隐式的,通过执行提供的函数,无论它是正常返回还是异常返回,或者通过完成一个先前的未来

    例如:

    • exceptionally如果前一个未来正常完成,则正常完成而不运行提供的函数

    • 所有其他链接方法,除了handleandwhenComplete及其*Async变体,如果先前的未来或组合 ( 和 ) 方法中的任何先前的未来异常完成,则在不运行提供的函数的情况*Both**Combine*异常*Either*完成

    • 否则,future 在提供的函数运行并正常或异常完成时完成

如果您创建的期货没有函数,或者它们没有链接到另一个未来,或者换句话说,如果它们没有关联的函数,那么它们只会显式完成,因此没有意义说如果这种可完成的未来运行,更不用说他们可能使用多个线程。

另一方面,如果期货具有功能,则取决于它们是如何创建的:

  • 如果它们都是独立的并使用ForkJoinPool.commonPool()(或缓存的线程池或类似的)作为执行器,那么它们可能会并行运行,可能使用与内核数量一样多的活动线程

  • 如果它们都相互依赖(除了一个)或者如果执行器是单线程的,那么它们将一次运行一个

  • 介于两者之间的任何内容都是有效的,例如:

    • 一些未来可能相互依赖,或者依赖于你不知道的其他内部未来

    • 某些未来可能是使用固定线程池执行程序创建的,您将在其中看到有限程度的并发运行任务

调用join不会告诉未来开始运行,它只是等待它完成。

所以,最后回答你的问题:

  • 如果未来有一个关联的函数,那么它可能已经在运行,它可能会或可能不会运行它的函数,这取决于它的链接方式和前一个未来的完成情况,如果它没有函数,它可能永远不会运行或者如果它在有机会运行其功能之前完成

  • 已经运行或将运行的期货这样做:

    • 在与*Async方法链接或使用带有执行程序的*Async静态方法创建时在提供的执行程序上

    • ForkJoinPool.commonPool()与方法链接或使用不带执行程序*Async的静态方法创建时*Async

    • 在没有方法的情况下链接它们所依赖的未来的同一线程上*Async,以防未来尚未完成

    • *Async在当前线程上,如果在没有方法的情况下链接它们所依赖的未来已经完成


在我看来,显式完成方法应该被隔离到一个 egCompletionSource接口,并有一个 egCompletableFutureSource类来实现它并提供一个未来,就像 .NET 的 aTaskCompletionSource和它的. 之间的关系Task

就像现在的情况一样,您很可能可以通过以非最初预期的方式完成它们来篡改您拥有的可完成期货。出于这个原因,你不应该CompletableFuture在公开后使用 a ;CompletableFuture从那时起,它就是您的 API 用户。

于 2016-06-03T11:55:03.323 回答
2

CompletableFuture 本身没有调度到线程(或核心)。任务是。要实现并行性,您需要创建多个任务。如果您返回 CompletableFuture 的方法提交任务,例如

返回 CompletableFuture.supplyAsync(this::calculate);

然后启动多个任务。如果他们只是创建 CompletableFuture 之类的

返回新的 CompletableFuture();

然后没有任务启动,也没有并行性。

CompletableFuture{handle, thenCombine, thenCompose, thenApply}创建的CompletableFuture对象没有连接到并行任务,所以并行度没有增加。

CompletableFuture{handleAsync, thenCombineAsync, thenComposeAsync, thenApplyAsync}创建的CompletableFuture对象连接到并行任务,但这些任务严格在CompletableFuture对象对应的任务之后执行this,因此无法增加并行度。

于 2016-06-02T04:37:22.807 回答