3

自古以来,同步/异步都是八股文第一章 - 博客猿马甲哥

 10 months ago
source link: https://www.cnblogs.com/JulianHuang/p/17511865.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

好久没上线了,今天记录编程中老掉牙的几个关键术语,一个言简意赅的术语定义包含主谓宾定状补, 我们应从貌似雷同的术语中体会到不同术语的表象行为、侧重点。

下面给出的3对技术术语,都是很核心、易混淆的概念点,但是多少还是有些表象、侧重点的不同。

书读百遍其义自见, 请关注最下方给出的微软官方技术文献, 自勉!!

1. 同步/异步、 阻塞/非阻塞

阻塞操作不等于同步,非阻塞操作也不等于异步。实际上,它们之间并没有直接的联系。

先说同步,这个很简单,就是按照代码来顺序执行。

比如下面这段伪代码:

local res, err  = query-mysql(sql)
local value, err = query-redis(key)

在同一请求连接中,如果要等 MySQL 的查询结果返回后,才能继续去查询 Redis,那就是同步;

如果不用等 MySQL 的返回,就能继续往下走,去查询 Redis,那就是异步。

完全不care MYSQL的查询结果,也不是业务想要的,一般的实践是query-mysql函数快速返回一个awaitable对象,通过状态查询、事件通知的方式拿到异步行为的结果。


再来说说非阻塞,这是一个很容易和“异步”混淆的概念。

这里我们说的“阻塞”,特指阻塞操作系统线程

我们继续看上面的例子,假设查询 MySQL 需要1s 的时间,如果在这1s 内,操作系统的资源(CPU)是空闲着并傻傻地等待返回,那就是阻塞;

如果 CPU 趁机去处理其他连接的请求,那就是非阻塞。

总体而言:

同步/异步虽然表现为函数调用,实际宏观上描述了一信息对齐方式, 异步调用,异步通信,异步任务均表现为发出通信动作后即刻返回,通过状态通知、回调函数来拿到通信结果。

阻塞/非阻塞关注的是应用程序在等待数据返回的状态问题:在得到结果之前,cpu若傻傻等待是阻塞(被挂起)。

.NET异步编程的三种套路

  1. 基于任务的异步模式 (TAP), 主流推荐
  2. 基于事件的异步模式 (EAP), 过时不推荐
  3. 异步编程模型 (APM) 模式(也称为 IAsyncResult 模式), 过时不推荐

2,3已经不被推荐(2,3其实很贴近异步的行为认知),目前主流推荐的TAP async/await语法糖,以同步姿势简化了异步编程, 但是语法糖也让我们不容易理解异步的本质: async/await语法糖具备传染性,导致async/await在整个代码结构泛滥使用,在被传染的async/await层级, 根本不体现通信交互,弱化了开发者对于最底层是异步通信的认知。

微软喜欢搞拖拽控件、语法糖给到开发者,让我们沉迷于便利的开发体验,忽视了朴素的核心本质。

2. 事件/消息

事件是对条件或状态更改的轻量级通知。

  • 事件的发布者对如何处理事件没有期望。
  • 事件的使用者决定如何处理通知。
  • 事件报告状态变化并且是可操作的, 要进行下一步,消费者只需要知道发生了什么。事件数据包含关于发生了什么事情的信息,但不包含触发事件的数据。例如,事件通知使用者文件已创建。它可能有关于文件的一般信息,但它没有文件本身。
  • 事件可以是离散的单位,也可以是一系列事件的一部分。
    一系列事件报告了一种状况,并且是可分析的。这些事件是按时间顺序排列并相互关联的。消费者可通过序列事件来分析发生了什么。

消息是由服务生成的原始数据,将在其他地方使用或存储 。

  • 消息包含触发消息管道的数据。
  • 消息的发布者对于消费者如何处理消息有一个期望。双方之间存在一份契约。
    例如,发布者发送带有原始数据的消息,并期望消费者从该数据创建文件,并在工作完成时发送响应。

3. 委托/事件

委托更像一个类的一个属性,只不过属性值是函数,公开的委托可以像类属性一样,自由赋值。

在众多语言中,委托与闭包密切相关。

和委托类似,事件也是后期绑定机制。 实际上,事件是建立在对委托的语言支持之上。

 In the .NET class library, events are based on the EventHandler delegate and the EventArgs base class.  
public delegate void EventHandler(object? sender, EventArgs e);

后期绑定机制: 组件通过调用可在运行时识别的方法进行通信。 它们都支持单个和多个订阅服务器方法。 这称为单播和多播支持。

两者均支持用于添加和删除处理程序的类似语法,引发事件和调用委托也是相同的调用语法。 它们甚至都支持与 ?. 运算符结合的 Invoke() 语法。

使用委托还是事件有一些考量:

事件是对条件或状态更改的轻量级通知。事件有可能被提前预置了反馈,也可能根本没预置反馈。

(1). 若侦听器可选,更倾向事件

A组件引发了事件,也许并不引发其他组件的连锁反应,也就是没有预置侦听器,这种虽然用委托也行,但是更倾向对事件赋值侦听器。

(2). 事件只能由定义事件的组件自行触发 ,而不能由外部触发。

包含事件的类以外的类只能添加和删除事件侦听器;只有包含事件的类才能引发事件。
还是那句话,事件更强调组件在满足条件或自身状态变更时触发。

(3). 事件不care侦听器的返回值

与(1)相关,因为事件的引发者本身也不care有没有侦听器。

搬砖多年,越来越体会到精准理解术语的重要性,一个言简意赅的术语定义 包含主谓宾定状补, 我们应从貌似雷同的术语中体会到不同术语的表象行为、侧重点。

上面三对概念:冥冥中存在某种微妙联系。

同步/异步: 描述了信息的对齐方式,如果是异步会即时返回,使用状态通知、回调事件来获得操作结果。

事件/消息:描述了信息的侧重点, 事件强调了某组件在满足某种条件、时间点而触发了某次行为,不care是否有消费方对这个行为产生了连锁反应。
消息是生产方要传递的原始数据,消息生产方对消息被消费是有期待的(存在消息格式便于消费方理解)。

委托/事件: 更接近于事件的技术实现,事件是基于委托实现的,事件更强调内生引发、委托可认为是类属性。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK