异步程序设计方式

目录

一、异步编程种类简介

二、线程

三、回调

四、Future、 Promise 及其他

五、反应式扩展

六、协程


一、异步编程种类简介

几十年以来,作为开发人员,我们面临着需要解决的问题——如何防止我们的应用程序被阻塞。 当我们正在开发桌面应用,移动应用,甚至服务器端应用程序时,我们希望避免让用户等待或导致更糟糕的原因成为阻碍应用程序扩展的瓶颈。

有很多途径来解决这种问题,包括:

  • 线程
  • 回调
  • Future、 Promise 及其他
  • 反应式扩展
  • 协程

二、线程

到目前为止,线程可能是最常见的避免应用程序阻塞的方法。

fun postItem(item: Item) {val token = preparePost()val post = submitPost(token, item)processPost(post)
}fun preparePost(): Token {// 发起请求并因此阻塞了主线程return token
}

让我们假设在上面的代码中,preparePost 是一个长时间运行的进程,因此会阻塞用户界面。我们可以做的是在一个单独的线程中启动它。这样就可以允许我们避免阻塞 UI。这是一种非常常见的技术,但有一系列缺点:

  • 线程并非廉价的。线程需要昂贵的上下文切换。
  • 线程不是无限的。可被启动的线程数受底层操作系统的限制。在服务器端应用程序中,这可能会导致严重的瓶颈。
  • 线程并不总是可用。在一些平台中,比如 JavaScript 甚至不支持线程。
  • 线程不容易使用。调试线程与避免竞争条件是我们在多线程编程中遇到的常见问题。

三、回调

使用回调,其想法是将一个函数作为参数传递给另一个函数,并在处理完成后调用此函数。

fun postItem(item: Item) {preparePostAsync { token -> submitPostAsync(token, item) { post -> processPost(post)}}
}fun preparePostAsync(callback: (Token) -> Unit) {// 发起请求并立即返回// 设置稍后调用的回调
}

原则上这感觉就像一个更优雅的解决方案,但又有几个问题:

  • 回调嵌套的难度。通常被用作回调的函数,经常最终需要自己的回调。这导致了一系列回调嵌套并导致出现难以理解的代码。该模式通常被称为标题圣诞树(大括号代表树的分支)。
  • 错误处理很复杂。嵌套模型使错误处理和传播变得更加复杂。

回调在诸如 JavaScript 之类的事件循环体系结构中非常常见,但即使在那里,通常人们已经转而使用其他方法,例如 promises 或反应式扩展。

四、Future、 Promise 及其他

futures 或 promises 背后的想法(这也可能会根据语言/平台而有不同的术语),是当我们发起调用的时候,我们承诺在某些时候它将返回一个名为 Promise 的可被操作的对象。

fun postItem(item: Item) {preparePostAsync() .thenCompose { token -> submitPostAsync(token, item)}.thenAccept { post -> processPost(post)}}fun preparePostAsync(): Promise<Token> {// 发起请求并当稍后的请求完成时返回一个 promisereturn promise 
}

这种方法需要对我们的编程方式进行一系列更改,尤其是:

  • 不同的编程模型。与回调类似,编程模型从自上而下的命令式方法转变为具有链式调用的组合模型。传统的编程结构例如循环,异常处理,等等。通常在此模型中不再有效。
  • 不同的 API。通常这需要学习完整的新 API 诸如 thenCompose 或 thenAccept,这也可能因平台而异。
  • 具体的返回值类型。返回类型远离我们需要的实际数据,而是返回一个必须被内省的新类型“Promise”。
  • 异常处理会很复杂。错误的传播和链接并不总是直截了当的。

五、反应式扩展

Erik Meijer) 将反应式扩展(Rx)引入了 C#. 虽然它在 .NET 平台上是毫无疑义的, 但是在 Netflix 将它移植到 Java 并取名为 RxJava 之前绝对不是主流。从那时起,反应式被移植到各种平台,包括 JavaScript(RxJS)。

Rx 背后的想法是走向所谓的“可观察流”,我们现在将数据视为流(无限量的数据),并且可以观察到这些流。 实际上,Rx 很简单, Observer Pattern 带有一系列扩展,允许我们对数据进行操作。

在方法上它与 Futures 非常相似,但是人们可以将 Future 视为一个离散元素,而 Rx 返回一个流。然而,与前面类似,它还介绍了一种全新的思考我们的编程模型的方式,著名的表述是:

“一切都是流,并且它是可被观察的”

这意味着处理问题的方式不同,并且在编写同步代码时从我们使用的方式发生了相当大的转变。与 Futures 相反的一个好处是,它被移植到这么多平台,通常我们可以找到一致的 API 体验,无论我们使用 C#、Java、JavaScript,还是 Rx 可用的任何其他语言。

此外,Rx 确实引入了一种更好的错误处理方法。

六、协程

Kotlin 编写异步代码的方式是使用协程,这是一种计算可被挂起的想法。即一种函数可以在某个时刻暂停执行并稍后恢复的想法。

协程的一个好处是,当涉及到开发人员时,编写非阻塞代码与编写阻塞代码基本相同。编程模型本身并没有真正改变。

以下面的代码为例:

fun postItem(item: Item) {launch {val token = preparePost()val post = submitPost(token, item)processPost(post)}
}suspend fun preparePost(): Token {// 发起请求并挂起该协程return suspendCoroutine { /* ... */ } 
}

此代码将启动长时间运行的操作,而不会阻塞主线程。preparePost 就是所谓的 可挂起的函数,因此它含有 suspend 前缀。这意味着如上所述,该函数将被执行、暂停执行以及在某个时间点恢复。

  • 该函数的签名保持完全相同。唯一的不同是它被添加了 suspend 修饰符。但是返回类型依然是我们想要的类型。
  • 编写这段代码代码就好像我们正在编写同步代码,自上而下,不需要任何特殊语法,除了使用一个名为 launch 的函数,它实质上启动了该协程(在其他教程中介绍)。
  • 编程模型和 API 保持不变。我们可以继续使用循环,异常处理等,而且不需要学习一整套新的 API。
  • 它与平台无关。无论我们是面向 JVM,JavaScript 还是其他任何平台,我们编写的代码都是相同的。编译器负责将其适应每个平台。

协程并不是一个新的概念,它并不是 Kotlin 发明的。它们已经存在了几十年,并且在 Go 等其他一些编程语言中很受欢迎。但重要的是要注意就是他们在 Kotlin 中实现的方式,大部分功能都委托给了库。事实上,除了 suspend 关键字,没有任何其他关键字被添加到语言中。这也是与其他语言的不同之处,例如 C# 将 async 以及 await 作为语法的一部分。而在 Kotlin 中,他们都只是库函数。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/68075.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

qt-Quick3D笔记之官方例程Runtimeloader Example运行笔记

qt-Quick3D笔记之官方例程Runtimeloader Example运行笔记 文章目录 qt-Quick3D笔记之官方例程Runtimeloader Example运行笔记1.例程运行效果2.例程缩略图3.项目文件列表4.main.qml5.main.cpp6.CMakeLists.txt 1.例程运行效果 运行该项目需要自己准备一个模型文件 2.例程缩略图…

以太坊入门【详解】

以太坊的组成部分 P2P网络&#xff1a;以太坊在以太坊网络上运行&#xff0c;该网络可在TCP端口30303上寻址&#xff0c;并运行一个协议。交易&#xff1a;以太坊交易时网络消息&#xff0c;其中包括发送者&#xff0c;接受者&#xff0c;值和数据的有效载荷以太坊虚拟机&…

实验十四 EL和JSTL

实验十四 EL和JSTL 一、实验目的 1、掌握EL表达式的使用 2、掌握JSTL的使用 二、实验过程 1、在数据库Book中建立表Tbook&#xff0c;包含图书ID&#xff0c;图书名称&#xff0c;图书价格。实现在bookQuery.jsp页面中模糊查询图书&#xff0c;如果图书的价格在50元以上&#…

安装和卸载RabbitMQ

我的飞书:https://rvg7rs2jk1g.feishu.cn/docx/SUWXdDb0UoCV86xP6b3c7qtMn6b 使用Ubuntu环境进行安装 一、安装Erlang 在安装RabbitMQ之前,我们需要先安装Erlang,RabbitMQ需要Erlang的语言支持 #安装Erlang sudo apt-get install erlang 在安装的过程中,会弹出一段信息,此…

音视频多媒体编解码器基础-codec

如果要从事编解码多媒体的工作&#xff0c;需要准备哪些更为基础的内容&#xff0c;这里帮你总结完。 因为数据类型不同所以编解码算法不同&#xff0c;分为图像、视频和音频三大类&#xff1b;因为流程不同&#xff0c;可以分为编码和解码两部分&#xff1b;因为编码器实现不…

ML基础-Jupyter notebook中的魔法命令

在 Jupyter Notebook 或 IPython 环境中&#xff0c;“魔法命令”&#xff08;Magic Commands&#xff09;是一些以百分号&#xff08;%&#xff09;或惊叹号&#xff08;!)开头的特殊命令&#xff0c;用于执行一些与代码运行环境相关的操作&#xff0c;而不仅仅是执行普通的 P…

【Unity2D 2022:UI】创建滚动视图

一、创建Scroll View游戏对象 在Canvas画布下新建Scroll View游戏对象 二、为Content游戏对象添加Grid Layout Group&#xff08;网格布局组&#xff09;组件 选中Content游戏物体&#xff0c;点击Add Competent添加组件&#xff0c;搜索Grid Layout Group组件 三、调整Grid La…

9-收纳的知识

[ComponentOf(typeof(xxx))]组件描述&#xff0c;表示是哪个实体的组件 [EntitySystemOf(typeof(xxx))] 系统描述 [Event(SceneType.Demo)] 定义事件&#xff0c;在指定场景的指定事件发生后触发 [ChildOf(typeof(ComputersComponent))] 标明是谁的子实体 [ResponseType(na…

数据库系统概念第六版记录 一

1.关系型数据库 关系型数据库&#xff08;Relational Database&#xff0c;简称 RDB&#xff09;是基于关系模型的一种数据库&#xff0c;它通过表格的形式来组织和存储数据。每个表由若干行&#xff08;记录&#xff09;和列&#xff08;字段&#xff09;组成&#xff0c;数据…

Vue前端开发-pinia之Actions插件

Store中的Actions部分&#xff0c;用于定义操作属性的方法&#xff0c;类似于组件中的methods部分&#xff0c;它与Getters都可以操作State属性&#xff0c;但在定义方法时&#xff0c;Getters是对State属性进行加工处理&#xff0c;再返回使用&#xff0c;属于内部计算;Action…

生成式AI安全最佳实践 - 抵御OWASP Top 10攻击 (下)

今天小李哥将开启全新的技术分享系列&#xff0c;为大家介绍生成式AI的安全解决方案设计方法和最佳实践。近年来生成式 AI 安全市场正迅速发展。据IDC预测&#xff0c;到2025年全球 AI 安全解决方案市场规模将突破200亿美元&#xff0c;年复合增长率超过30%&#xff0c;而Gartn…

一个开源 GenBI AI 本地代理(确保本地数据安全),使数据驱动型团队能够与其数据进行互动,生成文本到 SQL、图表、电子表格、报告和 BI

一、GenBI AI 代理介绍&#xff08;文末提供下载&#xff09; github地址&#xff1a;https://github.com/Canner/WrenAI 本文信息图片均来源于github作者主页 在 Wren AI&#xff0c;我们的使命是通过生成式商业智能 &#xff08;GenBI&#xff09; 使组织能够无缝访问数据&…

JAVA架构师进阶之路

JAVA架构师进阶之路 前言 苦于网络上充斥的各种java知识&#xff0c;多半是互相抄袭&#xff0c;导致很多后来者在学习java知识中味同嚼蜡&#xff0c;本人闲暇之余整理了进阶成为java架构师所必须掌握的核心知识点&#xff0c;后续会不断扩充。 废话少说&#xff0c;直接上正…

java程序员面试自身优缺点,详细说明

程序员面试大厂经常被问到的Java异常机制问题,你搞懂了吗运行时异常:运行时异常是可能被程序员避免的异常。与检查性相反,运行时异常可以在编译时被忽略。错误(ERROR):错误不是异常,而是脱离程序员控制的问题。错误通常在代码中容易被忽略。例如:当栈溢出时,一个错误就发生了,它…

C++六大默认成员函数

C六大默认成员函数 默认构造函数默认析构函数RAII技术RAII的核心思想优点示例应用场景 默认拷贝构造深拷贝和浅拷贝 默认拷贝赋值运算符移动构造函数&#xff08;C11起&#xff09;默认移动赋值运算符&#xff08;C11起&#xff09;取地址及const取地址操作符重载取地址操作符重…

防火墙的安全策略

1.VLAN 2属于办公区;VLAN 3属于生产区&#xff0c;创建时间段 [FW]ip address-set BG type object [FW-object-address-set-BG]address 192.168.1.0 mask 25 [FW]ip address-set SC type object [FW-object-address-set-SC]address 192.168.1.129 mask 25 [FW]ip address-se…

windows下搭建鸿蒙OS应用开发环境

一、前言 HUAWEI DevEco Studio 是华为推出的一款集成开发环境&#xff08;IDE&#xff09;&#xff0c;主要用于开发基于华为鸿蒙操作系统&#xff08;HarmonyOS&#xff09;的应用。作为华为开发者工具的核心之一&#xff0c;DevEco Studio 提供了一个多功能的开发平台&…

MacBook Pro(M1芯片)Qt环境配置

MacBook Pro&#xff08;M1芯片&#xff09;Qt环境配置 1、准备 试图写一个跨平台的桌面应用&#xff0c;此时想到了使用Qt&#xff0c;于是开始了搭建开发环境&#xff5e; 在M1芯片的电脑上安装&#xff0c;使用brew工具比较方便 Apple Silicon&#xff08;ARM/M1&#xf…

Sqlserver DBCC Check 遇到Msg 3853报错涉及sys.columns和sys.objects信息不匹配的解决方法

对数据库CacheDBMSIntl执行DBCC checkcatalog(‘CacheDBMSIntl’)时遇到报错如下 Msg 3853, Level 16, State 1, Line 7 Attribute (object_id1071830442) of row (object_id1071830442,column_id1) in sys.columns does not have a matching row (object_id1071830442) in sy…

VUE之组件通信(二)

1、v-model v-model的底层原理&#xff1a;是:value值和input事件的结合 $event到底是啥&#xff1f;啥时候能.target 对于原生事件&#xff0c;$event就是事件对象 &#xff0c;能.target对应自定义事件&#xff0c;$event就是触发事件时&#xff0c;所传递的数据&#xff…