【问题标题】:Java Stream vs Flux fromIterableJava Stream vs Flux fromIterable
【发布时间】:2019-12-04 15:40:56
【问题描述】:

我有一个用户名列表,想在不阻塞主线程的情况下从远程服务获取用户详细信息。我正在使用 Spring 的响应式客户端 WebClient。对于响应,我得到 Mono 然后订阅它并打印结果。

private Mono<User> getUser(String username) {
    return webClient
            .get()
            .uri(uri + "/users/" + username)
            .retrieve()
            .bodyToMono(User.class)
            .doOnError(e -> 
                logger.error("Error on retrieveing a user details {}", username));
}

我通过两种方式实现了这个任务:

使用Java stream

usernameList.stream()
          .map(this::getUser)
          .forEach(mono ->
                mono.subscribe(System.out::println));

使用Flux.fromIterable

Flux.fromIterable(usernameList)
        .map(this::getUser)
        .subscribe(mono ->
                mono.subscribe(System.out::println));

似乎主线程并没有被两种方式阻塞。 在这种情况下,Java StreamFlux.fromIterable 有什么区别?如果两者都在做同样的事情,建议使用哪一个?

【问题讨论】:

    标签: java spring java-stream spring-webflux spring-webclient


    【解决方案1】:

    这两种变体之间没有太大差异。 Flux.fromIterable 变体可能会为您提供更多选项并控制并发/重试等 - 但在这种情况下并非如此,因为在这里调用 subscribe 会破坏目的。

    您的问题缺少有关您正在构建的应用程序类型以及这些调用是在什么上下文中进行的一些背景知识。如果您正在构建一个 Web 应用程序,并且在请求处理或批处理应用程序期间调用它 - 意见可能会有所不同。

    总的来说,我认为应用程序应该远离调用subscribe,因为它会断开该管道的处理与应用程序的其余部分:如果发生异常,您可能无法报告它,因为要使用的资源那时发送该错误消息可能会消失。或者应用程序正在关闭,而您无法让它等待该任务的完成。

    如果您要构建的应用程序想要启动一些工作,并且其结果对当前操作没有用处(即,在当前操作的生命周期内该工作是否完成并不重要),那么subscribe 可能是一个选项。

    在这种情况下,我会尝试将所有操作分组到单个 Mono&lt;Void&gt; 操作中,然后触发该工作:

    Mono<Void> logUsers = Flux.fromIterable(userNameList)
        .map(name -> getUser(name))
        .doOnNext(user -> System.out.println(user)) // assuming this is non I/O work
        .then();
    logUsers.subscribe(...);
    

    如果您担心在 Web 应用程序中消耗服务器线程,那么情况就完全不同了——您可能希望获得该操作的结果,以便将某些内容写入 HTTP 响应。通过调用 subscribe,两个任务现在都已断开连接,并且在工作完成时 HTTP 响应可能早已消失(并且在写入响应时会出现错误)。

    在这种情况下,您应该将操作与 Reactor 操作符链接起来。

    【讨论】:

    • 它实际上是一个批处理应用程序,向用户发送电子邮件,推荐某种信息。你的样本真的很有用!
    • 我还有一个问题。还有另一个 API,我可以发送多个用户名并获取多个用户的信息作为响应。您认为一次获取​​所有结果并处理它还是发送多个并行请求更好?
    • 这取决于该方法在做什么;如果它并行发送多个请求,它可能是等效的。如果有一个特殊的 API 可以进行一次 HTTP 调用,那可能会更好。
    猜你喜欢
    • 1970-01-01
    • 2019-03-20
    • 1970-01-01
    • 1970-01-01
    • 2018-05-01
    • 2017-04-13
    • 1970-01-01
    • 1970-01-01
    • 2017-10-08
    相关资源
    最近更新 更多