(译)异步编程技术

原文链接

本教程介绍了异步编程的不同方法

几十年来,作为开发人员,我们面临着一个需要解决的问题 - 如何防止我们的应用进程被阻塞。无论我们是在开发桌面,移动还是服务器端应用进程,我们都希望避免让用户等待,或者更糟糕的是导致应用进程无法扩展的瓶颈。

有很多方法可以解决这个问题,包括:

  • 线程
  • 回调
  • Futures, Promises 等等
  • 响应式扩展
  • 协程

线程

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

12345678910
fun (item: Item) {    val token = preparePost()    val post = submitPost(token, item)    processPost(post)}

fun preparePost(): Token {

return token}

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

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

回调

使用回调,我们的想法是将一个函数作为参数传递给另一个函数,并在进程完成后调用此函数。

123456789101112
fun postItem(item: Item) {    preparePostAsync { token ->         submitPostAsync(token, item) { post ->             processPost(post)        }    }}

fun preparePostAsync(callback: (Token) -> Unit) {    // make request and return immediately     // arrange callback to be invoked later}

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

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

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

Futures,Promises 等等

Future 或Promise背后的思想(也可以根据语言/平台提及其他术语)是,当我们调用的时候,我们承诺在某些时候它会返回一个名为Promise的对象,然后在这个对象上可以操作。

123456789101112131415
fun postItem(item: Item) {    preparePostAsync()         .thenCompose { token ->             submitPostAsync(token, item)        }        .thenAccept { post ->             processPost(post)        }

}

fun preparePostAsync(): Promise<Token> {

return promise }

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

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

响应式扩展

Reactive Extensions(Rx)由Erik Meijer引入C#。虽然它确实在.NET平台上使用,但它确实没有达到主流采用,直到Netflix将其移植到Java,命名为RxJava。从那时起,已经为各种平台提供了许多端口,包括JavaScript(RxJS)。

Rx背后的想法是转向所谓的可观察流,我们现在将数据视为流(无限量的数据),并且可以观察到这些流。实际上,Rx只是具有一系列扩展的观察者模式,它允许我们对数据进行操作。

在方法中它与 Futures 非常相似,但是人们可以将 Future 视为返回离散元素,从而Rx返回一个流。然而,与之前的类似,它还引入了一种全新的思考我们的编程模型的方式,着名的是

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

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

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

协程

kotlin使用异步代码的方法是使用协同进程,这是可暂停计算的想法,即一个函数可以在某个时刻暂停执行并稍后恢复的想法。

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

以下面的代码为例

123456789101112
fun postItem(item: Item) {    launch {        val token = preparePost()        val post = submitPost(token, item)        processPost(post)    }}

suspend fun preparePost(): Token {    // makes a request and suspends the coroutine    return suspendCoroutine { /* ... */ } }

此代码将启动长时间运行的操作,而不会阻塞主线程。 preparePost是所谓的可挂起函数,因此关键字 suspend 为它添加前缀。如上所述,这意味着该功能将在某个时间点执行,暂停执行和恢复。

  • 功能签名保持完全相同。唯一的区别是暂停被添加到它。但返回类型是我们想要返回的类型。
  • 代码仍然被编写为好像我们正在编写同步代码,自上而下,不需要任何特殊语法,除了使用一个名为 launch 的函数,它基本上启动了协同进程(在其他教程中介绍)。
  • 编程模型和API保持不变。我们可以继续使用循环,异常处理等,而且不需要学习一整套新的API
  • 它与平台无关。无论我们是针对JVM,JavaScript 还是其他任何平台,我们编写的代码都是相同的。表现之下,编译器负责将其适应每个平台。
  • 协同进程不是一个新概念,更不用说是由 Kotlin 发明了。它们已经存在了几十年,并且在Go等其他编程语言中很受欢迎。值得注意的是,它们在 Kotlin 中的实现方式,大部分功能都委托给了库。事实上,除了 suspend 关键字之外,该语言中没有添加其他关键字。这与C#之类的语言略有不同,这些语言具有异步并等待语法的一部分。使用 Kotlin,这些只是库函数。

有关协同进程和不同可能性的更多信息,请查看参考指南。

原文:大专栏  (译)异步编程技术

原文地址:https://www.cnblogs.com/petewell/p/11422406.html

时间: 2024-11-06 09:51:13

(译)异步编程技术的相关文章

如何提高Web服务端并发效率的异步编程技术

作为一名web工程师都希望自己做的web应用能被越来越多的人使用,如果我们所做的web应用随着用户的增多而宕机了,那么越来越多的人就会变得越来越少了,为了让我们的web应用能有更多人使用,我们就得提升web应用服务端的并发能力.那么我们如何做到这点了,根据现有的并发技术我们会有如下选择: 第一个做法:为每个客户端发送给服务端的请求都开启一个线程,等请求处理完毕后该线程就被销毁掉,这种做法很直观,但是在现代的web服务器里这种做法已经很少使用了,原因是新建一个线程,销毁一个线程的开销(开销是指占用

如何正确运用异步编程技术

一.什么是同步和异步? 同步(英语:Synchronization),指对在一个系统中所发生的事件(event)之间进行协调,在时间上出现一致性与统一化的现象.说白了就是多个任务一个一个执行,同一时刻只有一个任务在执行. 异步(英语:Asynchronization),指的是让CPU暂时搁置当前请求的响应,处理下一个请求,当通过轮询或其他方式得到回调通知后,开始运行.多线程将异步操作放入另一线程中运行,通过轮询或回调方法得到完成通知,但是完成端口,由操作系统接管异步操作的调度,通过硬件中断,在完

ASP.NET MVC如何正确运用异步编程技术

一.什么是同步和异步? 同步(英语:Synchronization),指对在一个系统中所发生的事件(event)之间进行协调,在时间上出现一致性与统一化的现象.说白了就是多个任务一个一个执行,同一时刻只有一个任务在执行. 异步(英语:Asynchronization),指的是让CPU暂时搁置当前请求的响应,处理下一个请求,当通过轮询或其他方式得到回调通知后,开始运行.多线程将异步操作放入另一线程中运行,通过轮询或回调方法得到完成通知,但是完成端口,由操作系统接管异步操作的调度,通过硬件中断,在完

Atitit.异步编程技术原理与实践attilax总结

1. 俩种实现模式 类库方式,以及语言方式,java futuretask ,c# await1 2. 事件(中断)机制1 3. Await 模式(推荐)1 4. Java的实现模式futuretask 对于c#的task类库(推荐)1 4.1. 使用Java 8的CompletableFuture实现函数式的回调.htm2 5. Timer模式2 6. Thread模式(不推荐,太底层)2 1. 俩种实现模式 类库方式,以及语言方式,java futuretask ,c# await 2. 事

NODE编程(二)--异步编程技术

在Node世界里流行两种响应逻辑管理方式,回调和事件监听. 回调通常用来定义一次性响应的逻辑.比如对于数据的查询,可以指定一个回调函数来确定如何处理查询结果. 事件监听器,本质上也是一个回调,不同的是,它跟一个概念实体(事件)相关联.在Node中,当有HTTP请求过来是,HTTP服务器会发出一个请求事件.你可以监听这个请求事件,并添加一些响应逻辑. 一.用回调处理一次性事件 回调是一个函数,它被当做参数传给异步函数,它描述了异步操作完成之后要做什么. /*在简单的程序重使用回调*/ var ht

异步编程和线程的使用(.NET 4.5 )

C#:异步编程和线程的使用(.NET 4.5 ) 异步编程和线程处理是并发或并行编程非常重要的功能特征.为了实现异步编程,可使用线程也可以不用.将异步与线程同时讲,将有助于我们更好的理解它们的特征. 本文中涉及关键知识点 1. 异步编程 2. 线程的使用 3. 基于任务的异步模式 4. 并行编程 5. 总结 异步编程 什么是异步操作?异步操作是指某些操作能够独立运行,不依赖主流程或主其他处理流程.通常情况下,C#程序从Main方法开始,当Main方法返回时结束.所有的操作都是按顺序执行的.执行操

【Node.js基础篇】(七)Node异步编程之事件发射器

事件发射器是Node里除了回调函数外的另一十分重要的异步编程技术. 在MFC等图形界面编程库中,事件发射器是非常常见的,比如,鼠标点击事件,点击了鼠标后,就会触发鼠标点击后的函数--事件发射器触发事件,并且在事件被触发后处理它们.在Node API组件中,如HTTP服务器.TCP服务器等都被做成了事件发射器,所以掌握事件发射器的编程方法,是非常重要的. 使用on添加监听器 步骤: 声明事件发射器类 创建事件发射器对象 使用on添加事件发射器 使用emit发射事件 //事件发射器类声明 var E

C#:异步编程和线程的使用(.NET 4.5 )

C#:异步编程和线程的使用(.NET 4.5 ) 异步编程和线程处理是并发或并行编程非常重要的功能特征.为了实现异步编程,可使用线程也可以不用.将异步与线程同时讲,将有助于我们更好的理解它们的特征. 本文中涉及关键知识点 1. 异步编程 2. 线程的使用 3. 基于任务的异步模式 4. 并行编程 5. 总结 异步编程 什么是异步操作?异步操作是指某些操作能够独立运行,不依赖主流程或主其他处理流程.通常情况下,C#程序从Main方法开始,当Main方法返回时结束.所有的操作都是按顺序执行的.执行操

异步编程 In .NET

概述 在之前写的一篇关于async和await的前世今生的文章之后,大家似乎在async和await提高网站处理能力方面还有一些疑问,博客园本身也做了不少的尝试.今天我们再来回答一下这个问题,同时我们会做一个async和await在WinForm中的尝试,并且对比在4.5之前的异步编程模式APM/EAP和async/await的区别,最后我们还会探讨在不同线程之间交互的问题. IIS存在着处理能力的问题,但是WinForm却是UI响应的问题,并且WinForm的UI线程至始至终都是同一个,所以两