是否可以使用Java 8 Streams API进行异步处理?

时间:2013-07-31 02:33:15

标签: java asynchronous java-8 java-stream

我一直在使用Java 8中的CompletionStage / CompletableFuture进行异步处理,这非常有效。但是,有时我想要一个阶段来执行迭代器/项目流的异步处理,似乎没有办法做到这一点。

具体来说,Stream.forEach()具有语句,在调用之后所有项都已处理完毕。我想要相同的东西,但改为使用CompletionStage,例如:

CompletionStage<Void> done = stream.forEach(...);
done.thenRun(...);

如果Stream由异步流式传输结果支持,那么等待它在上面的代码本身中完成要好得多。

是否有可能以某种方式使用当前的Java 8 API构建它?解决方法?

5 个答案:

答案 0 :(得分:21)

据我所知,streams API不支持异步事件处理。听起来你想要像Reactive Extensions for .NET这样的东西,它有一个名为RxJava的Java端口,由Netflix创建。

RxJava支持许多与Java 8流相同的高级操作(例如map和filter),并且是异步的。

更新:现在正在开展reactive streams计划,看起来JDK 9将通过Flow类至少支持部分内容。

答案 1 :(得分:7)

正如@KarolKrol所暗示,您可以使用CompletableFuture的流来完成。

有一个基于JDK8流构建的库,以便于处理名为cyclops-reactCompletableFuture流。

要编写你的流你可以使用cyclops-react的流畅的promise ike API,或者你可以使用simple-react的Stages

答案 2 :(得分:3)

cyclops-react(我是这个库的作者),提供了一个用于处理Streams的StreamUtils类。 它提供的功能之一是futureOperations,它提供对标准Stream终端操作(然后是一些)的访问 - Stream是异步执行的,结果在CompletableFuture中返回。 .e.g

 Stream<Integer> stream = Stream.of(1,2,3,4,5,6)
                                       .map(i->i+2);
 CompletableFuture<List<Integer>> asyncResult =  StreamUtils.futureOperations(stream,
                                             Executors.newFixedThreadPool(1))
                                       .collect(Collectors.toList());

还有一个包含Stream的概念类ReactiveSeq并提供相同的功能,并提供了一个不错的流畅API

 CompletableFuture<List<Integer>> asyncResult = ReactiveSeq.of(1,2,3,4,5,6)
                                       .map(i->i+2)
                                       .futureOperations(
                                             Executors.newFixedThreadPool(1))
                                       .collect(Collectors.toList());

正如Adam所指出的那样cyclops-react FutureStreams旨在异步处理数据(通过将Futures和Streams混合在一起) - 它特别适用于涉及阻塞I / O的多线程操作(例如读取文件,进行db调用,进行休息调用等。)

答案 3 :(得分:1)

可以生成一个流,将每个元素映射到CompletionStage,然后使用CompletionStage.thenCombine()收集结果,但是生成的代码将不会更简单,因此使用simple就像这样。

    CompletionStage<Collection<Result>> collectionStage =
        CompletableFuture.completedFuture(
            new LinkedList<>()
        );

    for (Request request : requests) {
        CompletionStage<Result> resultStage = performRequest(request);
        collectionStage = collectionStage.thenCombine(
            resultStage,
            (collection, result) -> {
                collection.add(result);
                return collection;
            }
        );
    }

    return collectionStage;

这个例子可以很容易地转换为功能性,而不会失去可读性。但是使用流的reducecollect需要额外的不太好的代码。

更新:CompletableFuture.allOfCompletableFuture.join提供了另一种更易读的方式,可将未来结果的收集转换为未来的结果集合。

答案 4 :(得分:0)

如前所述,使用反应式编程:

Maven:
groupId:org.projectreactor
artifactId:反应器弹簧

例:

Flux.fromIterable(Arrays.asList("een", "twee"))
    .flatMap(string -> translateDutchToEnglish(string))
    .parallel()
    .runOn(Schedulers.parallel())
    .sequential()
    .collectList()
    .block();

它的作用是创建一个Flux,该Flux是一组可解析的项目,您可以在其上执行操作:带有回调的flatMap。
然后,使用parallel()方法使其异步。 runOn()用于指示在哪个线程上运行它。 Schedulers.parallel()表示使用的线程数与CPU内核数一样。
sequence()将其恢复为同步状态,以使collectList()再次将所有结果收集到一个列表中。
要等待所有线程完成其业务,请使用block()。结果是带有结果的列表。