简体   繁体   English

CompletableFuture:等待完成百分比

[英]CompletableFuture: Await percentage complete

I am writing identical data in parallel to n nodes of a distributed system.我正在将相同的数据并行写入分布式系统的 n 个节点。
When n% of these nodes have been written to successfully, the remaining writes to the other nodes are unimportant as n% guarantees replication between the other nodes.当这些节点中的 n% 已成功写入时,其余对其他节点的写入并不重要,因为 n% 保证了其他节点之间的复制。

Java's CompletableFuture seems to have very close to what I want eg: Java 的 CompletableFuture 似乎与我想要的非常接近,例如:

CompletableFuture.anyOf()

(Returns when the first future is complete) - avoids waiting unnecessarily, but returns too soon as I require n% completions (在第一个未来完成时返回) - 避免不必要的等待,但在我需要 n% 完成时返回太快

CompletableFuture.allOf()

(Returns when all futures complete) - avoids returning too soon but waits unnecessarily for 100% completion (在所有期货完成时返回)- 避免过早返回但不必要地等待 100% 完成

I am looking for a way to return when a specific percentage of futures have completed.我正在寻找一种在特定百分比的期货完成时返回的方法。 For example if I supply 10 futures, return when 6 or 60% of these complete successfully.例如,如果我提供 10 个期货,当其中 6% 或 60% 成功完成时返回。

For example, Bluebird JS has this feature with例如, Bluebird JS具有此功能

Promise.some(promises, countThatNeedToComplete)

I was wondering if I could do something similar with TheadExecutor or vanilla CompletableFuture in java我想知道我是否可以在 java 中使用 TheadExecutor 或 vanilla CompletableFuture 做类似的事情

I believe you can achieve what you want using only what's already provided by CompletableFuture , but you'll have to implement additional control to know how many future tasks were already completed and, when you reach the number/percentage that you need, cancel the remaining tasks.我相信你可以只使用CompletableFuture已经提供的东西来实现你想要的,但是你必须实施额外的控制来知道有多少未来的任务已经完成,当你达到你需要的数量/百分比时,取消剩下的任务。

Below is a class to illustrate the idea:下面是一个 class 来说明这个想法:

public class CompletableSome<T>
{
private List<CompletableFuture<Void>> tasks;
private int tasksCompleted = 0;

public CompletableSome(List<CompletableFuture<T>> tasks, int percentOfTasksThatMustComplete)
{
    int minTasksThatMustComplete = tasks.size() * percentOfTasksThatMustComplete / 100;
    System.out.println(
        String.format("Need to complete at least %s%% of the %s tasks provided, which means %s tasks.",
            percentOfTasksThatMustComplete, tasks.size(), minTasksThatMustComplete));

    this.tasks = new ArrayList<>(tasks.size());
    for (CompletableFuture<?> task : tasks)
    {
        this.tasks.add(task.thenAccept(a -> {
            // thenAccept will be called right after the future task is completed. At this point we'll
            // check if we reached the minimum number of nodes needed. If we did, then complete the 
            // remaining tasks since they are no longer needed.
            tasksCompleted++;
            if (tasksCompleted >= minTasksThatMustComplete)
            {
                tasks.forEach(t -> t.complete(null));
            }
        }));
    }
}

public void execute()
{
    CompletableFuture.allOf(tasks.toArray(new CompletableFuture<?>[0])).join();
}
}

You would use this class as in the example below:您将使用此 class,如下例所示:

public static void main(String[] args)
{
    int numberOfNodes = 4;

    // Create one future task for each node.
    List<CompletableFuture<String>> nodes = new ArrayList<>();
    for (int i = 1; i <= numberOfNodes; i++)
    {
        String nodeId = "result" + i;
        nodes.add(CompletableFuture.supplyAsync(() -> {
            try
            {
                // Sleep for some time to avoid all tasks to complete before the count is checked.
                Thread.sleep(100 + new Random().nextInt(500));
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }

            // The action here is just to print the nodeId, you would make the actual call here.
            System.out.println(nodeId + " completed.");
            return nodeId;
        }));
    }

    // Here we're saying that just 75% of the nodes must be called successfully.
    CompletableSome<String> tasks = new CompletableSome<>(nodes, 75);
    tasks.execute();
}

Please note that with this solution you could end up executing more tasks than the minimum required -- for instance, when two or more nodes respond almost simultaneously, you may reach the minimum required count when the first node responds, but there will be no time to cancel the other tasks.请注意,使用此解决方案,您最终可能会执行比最低要求更多的任务 - 例如,当两个或更多节点几乎同时响应时,您可能会在第一个节点响应时达到所需的最低计数,但没有时间取消其他任务。 If that's an issue, then you'd have to implement even more controls.如果这是一个问题,那么您将不得不实施更多控制。

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

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