Mono 与 CompletableFuture

2024-04-25

CompletableFuture在单独的线程上执行任务(使用线程池)并提供回调函数。假设我有一个 API 调用CompletableFuture。这是 API 调用阻塞吗?线程会被阻塞直到它没有从 API 得到响应吗? (我知道主线程/tomcat线程将是非阻塞的,但是正在执行CompletableFuture任务的线程呢?)

据我所知,Mono 是完全非阻塞的。

如果我错了,请澄清这一点并纠正我。


CompletableFuture 是异步的。但它是非阻塞的吗?

CompletableFuture 的一个事实是它是真正的异步,它允许您从调用者线程和 API 异步运行任务,例如thenXXX允许您在结果可用时对其进行处理。另一方面,CompletableFuture并不总是非阻塞的。例如,当您运行以下代码时,它将在默认情况下异步执行ForkJoinPool:

CompletableFuture.supplyAsync(() -> {
    try {
        Thread.sleep(1000);
    }
    catch (InterruptedException e) {

    }

    return 1;
});

很明显,Thread in ForkJoinPool执行任务的函数最终会被阻塞,这意味着我们不能保证调用是非阻塞的。

另一方面,CompletableFuture公开 API,使您能够真正做到非阻塞。

例如,您始终可以执行以下操作:

public CompletableFuture myNonBlockingHttpCall(Object someData) {
    var uncompletedFuture = new CompletableFuture(); // creates uncompleted future

    myAsyncHttpClient.execute(someData, (result, exception -> {
        if(exception != null) {
            uncompletedFuture.completeExceptionally(exception);
            return;
        }
        uncompletedFuture.complete(result);
    })

    return uncompletedFuture;
}

如您所见,APICompletableFuture未来为您提供complete and completeExceptionally方法可以在需要时完成执行,而不会阻塞任何线程。

Mono 与 CompletableFuture

在上一节中,我们概述了 CF 的行为,但是 CompletableFuture 和 Mono 之间的主要区别是什么?

值得一提的是,我们也可以阻塞 Mono。没有人阻止我们写以下内容:

Mono.fromCallable(() -> {
    try {
        Thread.sleep(1000);
    }
    catch (InterruptedException e) {

    }

    return 1;
})

当然,一旦我们订阅了 future,调用者线程就会被阻塞。但我们总是可以通过提供额外的解决方案来解决这个问题subscribeOn操作员。尽管如此,更广泛的 APIMono不是关键功能。

为了了解之间的主要区别CompletableFuture and Mono,让我们回到前面提到的myNonBlockingHttpCall方法实施。

public CompletableFuture myUpperLevelBusinessLogic() {
    var future = myNonBlockingHttpCall();

    // ... some code

    if (something) {
       // oh we don't really need anything, let's just throw an exception
       var errorFuture = new CompletableFuture();
       errorFuture.completeExceptionally(new RuntimeException());

       return errorFuture;
    }

   return future;
}

如果是CompletableFuture,一旦调用该方法,它将急切地执行对另一个服务/资源的 HTTP 调用。即使在验证某些前置/后置条件后我们并不真正需要执行结果,它也会开始执行,并且将为这项工作分配额外的 CPU/DB-Connections/What-Ever-Machine-Resources。

相比之下,Mono根据定义,类型是惰性的:

public Mono myNonBlockingHttpCallWithMono(Object someData) {
    return Mono.create(sink -> {
            myAsyncHttpClient.execute(someData, (result, exception -> {
                if(exception != null) {
                    sink.error(exception);
                    return;
                }
                sink.success(result);
            })
    });
} 

public Mono myUpperLevelBusinessLogic() {
    var mono = myNonBlockingHttpCallWithMono();

    // ... some code

    if (something) {
       // oh we don't really need anything, let's just throw an exception

       return Mono.error(new RuntimeException());
    }

   return mono;
}

在这种情况下,直到最后一刻都不会发生任何事情mono已订阅。因此,只有当Mono由返回myNonBlockingHttpCallWithMono方法,将被订阅,逻辑提供给Mono.create(Consumer)将被执行。

我们还可以走得更远。我们可以让我们的执行更加懒惰。你可能知道,Mono延伸Publisher来自反应流规范。 Reactive Streams 的一大特色是背压支持。因此,使用Mono仅当确实需要数据并且我们的订阅者准备好使用它们时,我们才能执行 API:

Mono.create(sink -> {
    AtomicBoolean once = new AtomicBoolean();
    sink.onRequest(__ -> {
        if(!once.get() && once.compareAndSet(false, true) {
            myAsyncHttpClient.execute(someData, (result, exception -> {
                if(exception != null) {
                    sink.error(exception);
                    return;
                }
                sink.success(result);
            });
        }
    });
});

在此示例中,我们仅在订阅者调用时才执行数据Subscription#request因此,它通过这样做来声明已准备好接收数据。

Summary

  • CompletableFuture是异步的并且可以是非阻塞的
  • CompletableFuture很渴望。你不能推迟执行。但你可以取消它们(这比什么都没有好)
  • Mono是异步/非阻塞的,可以轻松地执行不同的调用Thread通过编写主要Mono与不同的运营商。
  • Mono确实是懒惰的,并且允许通过订阅者的存在及其消费数据的准备情况来推迟执行启动。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Mono 与 CompletableFuture 的相关文章

随机推荐

  • 如何将数组(在 VB6 中通过引用)传递给 C\C++ *.dll 子例程?

    我需要将一个空的变体数组传递给一个用 C 编写的 DLL 并且在所有 Windows 版本上都可用 并且 C 代码 我无法控制也无法编辑 将用它的一些返回值填充空的变体数组价值观 基本上 当我尝试这样做时 ByRef 数组在应包含函数 子调
  • 如何使用 php 注销后终止会话

    我看到了以下问题并尝试调整部分答案 但没有成功 用户按注销并销毁会话后如何禁用后退浏览器按钮 我知道这个话题已经被广泛讨论 人们讨厌 禁用后退按钮 这句话 但是 如果我有一个包含重要信息的数据库 一旦该人注销 我如何防止某人按下后退按钮并返
  • 使用 sprintf 打印元素数量可变的向量

    在下面的代码中 我可以打印向量中的所有元素item用空格分隔为 item 123 456 789 sprintf d d d item ans 123 456 789 我怎样才能做到这一点而不必输入那么多 d作为元素的数量item 最简单的
  • AWS S3 列表键以字符串开头

    我在 AWS Lambda 函数中使用 python 列出以特定 id 开头的 s3 存储桶中的键 for object in mybucket objects all file name os path basename object k
  • 使用 Electron 和 Systemjs 导入节点模块

    我只是想知道如果系统js在自己的注册表中找不到该模块 是否可以让systemjs使用require remote require nodemodule 我认为当使用带有 typescript 和 commonjs 模块的 Electron
  • 一个包中的多个模块导入一个公共模块

    我正在写一个 python 包 我使用插件的概念 每个插件都是 Worker 类的专门化 每个插件都被编写为模块 脚本 并在单独的进程中生成 由于插件之间的基本共性 例如 所有插件都扩展基类 Worker 插件模块通常如下所示 import
  • 为什么 VBA 中的 GetValue 函数使用单元格“A1”?

    我正在使用此函数从关闭的工作簿中检索值 在此代码的第 8 行中 我不明白为什么使用 A1 整个第 8 行到底发生了什么 我也对 xlR1C1 的论点感到困惑 Private Function GetValue path file sheet
  • 使用 C# 将 JSON 字符串从 Camel 大小写转换为 Pascal 大小写

    我有一个 JSON 字符串 它的密钥采用驼峰式大小写形式 但我需要将密钥转换为帕斯卡式大小写 实际的 JSON 字符串 string jsonString personName firstName Emma lastName Watson
  • Android TabWidget 检测当前选项卡的点击

    我正在尝试找到一种方法 当该选项卡是当前选项卡时 能够在该选项卡上触发 onclick 事件 我确实尝试过这种方式 以及其他几种方式 但没有成功 public void onTabChanged String tabId Log d thi
  • 在 Java 中使用 JSON 的 HTTP POST

    我想在 Java 中使用 JSON 制作一个简单的 HTTP POST 假设网址是www site com 它接受值 name myname age 20 标记为 details 例如 我将如何创建 POST 语法 我似乎也无法在 JSON
  • 背景 x 重复负边距重叠

    实际上是我关于堆栈的第一个问题 我试图在重复背景上获得负 右 边距 这样重复图像之间就不会出现间隙 似乎没有 CSS 语法来实现这一点 为了清楚起见 我在下面添加了一张图片 所以我试图让类似饼干的东西的重复图像重叠 这样它们之间就没有间隙
  • 如果我们在更大的表中使用广播会发生什么?

    我想知道如果我们广播较大的表并将其加入到较小的表中会发生什么 另外 如果我们有两个同样大的表 在这种情况下使用广播连接会发生什么 有几件事需要考虑 火花上限 Spark支持最大8GB的广播表 如果你的广播对象超过这个数量 它就会失败 驱动程
  • 最新的CEDET版本无法加载语义包

    我在加载 Alex Ott 推荐的一些语义包时遇到问题他著名的 CEDET 指南 http alexott net en writings emacs devenv EmacsCedet html使用最新版本的 CEDET 时 我之前的设置
  • 在Python 3中从CGI输出二进制数据

    这个问题与this one https stackoverflow com q 908331 554319 我在从 Python 2 中的 CGI 脚本打印原始二进制数据时没有遇到任何问题 例如 usr bin env python2 im
  • 一元加号和减号运算符的重要用途是什么?

    如果一元 运算符用于执行转换Number 转换函数 那么为什么我们需要一元运算符呢 这些一元运算符有什么特殊需要 一元论 运算符将其操作数转换为 Number 类型 一元论 运算符将其操作数转换为 Number 类型 然后将其取反 根据EC
  • Sublime 代码折叠注释(如 Ace 中)

    在 Cloud9 基于 Ace 编辑器 中 我可以在注释中定义任意代码折叠区域 例如 Descriptor function Code 折叠为 Descriptor lt gt 在这里尝试看看我的意思 http ace c9 io buil
  • ModelClientValidationRule 冲突

    我已将 vs 2011 开发人员预览版与 vs 2010 并排安装 现在 当我在 vs 2010 中运行我的 asp net mvc 3 项目时 我在使用 ModelClientValidationRule 的项目中收到以下错误 Syste
  • 在线代码美化器和格式化程序[关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 在一个函数中返回两个变量[重复]

    这个问题在这里已经有答案了 考虑以下代码 demo http jsfiddle net m59Fg function test var h Hello var w World return h w var test test alert t
  • Mono 与 CompletableFuture

    CompletableFuture在单独的线程上执行任务 使用线程池 并提供回调函数 假设我有一个 API 调用CompletableFuture 这是 API 调用阻塞吗 线程会被阻塞直到它没有从 API 得到响应吗 我知道主线程 tom