在我们编程的时候,经常会遇到一个概念——异步,诸如异步通信,异步线程,异步代码,异步调用,异步编程等等,那么

什么是异步呢?

为什么要异步?

异步的典型场景是什么?

如何使用异步呢?

......

异步——通信?

老码农初识异步是从单片机的串行通信开始的。串行通信,是指通信双方按位进行,遵守时序的一种通信方式。串行通信有两种类型,一种是同步通信,另一种就是异步通信。

同步通信的特点是要求发送时钟和接收时钟保持严格的同步,异步通信的发送端和接收端可以由各自的时钟来控制数据的发送和接收,这两个时钟源彼此独立,互不同步。异步通信中的接收方并不知道数据什么时候会到达,发送方发送的时间间隔可以不均匀,接收方是在数据的起始位和停止位的帮助下实现信息同步的。简单的说,异步是扔出去一段数据,对方靠着内容前后所检查到的特殊性发现了它,把这个内容存下来;而同步通信是对方在时刻等着发送方发号施令,发送方告诉对方要发送了,然后双方一拍即合。

从通信效率来看,同步通信效率高,异步通信效率较低。但从实现方式来看,同步通信较复杂,异步通信相对简单,计算机的接口大多是异步的。

进一步,对通信网络而言,同步网一般是指网络内所有电信设备的时钟(或载波)提供同步控制信号,使它们的频率工作在共同速率(或频率)上的支撑网。同步网可分为准同步网和同步网两类,由具有相同标称频率的不同基准时钟互相比对的同步网称为准同步网,由单一基准时钟控制的称为同步网。我国和大多数国家采用分级主从同步法,国家间采用准同步法。异步网络不需要时间同步,可以在任何节点完成逐分组的转发,这种分组的不可预测和不规则机制增加了网络的阻塞率。然而,异步网络具有同步网络所不具备的低成本、低复杂度、高健壮性和高灵活性,通过合理设计交换的结构和协议,也可达到良好的交换性能。

关于通信网乃至TMN,太容易给人带来回忆了。跳出涌现的往事,对程序员而言,异步的概念有了相当程度的延伸。

c/c++Linux后台服务器开发视频资料+主页qun获取

异步——编程?

编程中的同步与异步往往是指两个对象之间的调用关系:

  • 同步调用:调用者发出一个调用时,在没有得到结果之前,该调用不返回。一旦调用返回,就得到返回值了,也就是由调用者主动等待这个调用的结果。
  • 异步调用:调用者发出一个调用之后,这个调用就直接返回了,没有返回结果,也就是当一个异步调用发出后,调用者不会立刻得到结果。而是在调用发出之后,被调用者通过状态、消息等来通知调用者,或通过回调函数处理这个调用。

对于异步编程而言,和软件系统的架构设计有类似的地方,大体上,可以分为面向CPU的异步编程和面向IO的异步编程这两种方式。

面向CPU 的异步

我们常见的多线程中就会经常遇到面向CPU的异步编程。线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。同步线程是指两个线程的运行是相关的,其中一个线程可能要阻塞等待另外一个线程的运行。异步线程是两个线程毫不相关,自己运行自己的。

这里也经常遇到另外的两个概念——阻塞和非阻塞,在多线程编程中,主要是指线程是否需要等待。阻塞调用指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。非阻塞调用是指在不能立刻得到结果之前,该调用不会阻塞当前线程。

在Android上编程的时候,UI主线程和子线程的交互几乎是不可或缺的。在服务器侧,同样如此,SpringBoot 中配置异步线程池的简单示例如下:

//启动异步
@EnableAsync
//配置类
@Configuration
class ThreadsPoolConfig {
@Bean("taskExecutor")
public Executor taskExecutor() {
//创建建线程池
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//初始的线程数量
executor.setCorePoolSize(INI_THREAD_NUM);
//最大的线程数量
executor.setMaxPoolSize(MAX_THREAD_NUM);
//队列的最大容量
executor.setQueueCapacity(MAX_QUEUE_CAP);
//存活时间
executor.setKeepAliveSeconds(ALIVE_TIME);
//线程池的饱和策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
//关闭线程池时是否等待任务完成
executor.setWaitForTasksToCompleteOnShutdown(true);
//等待终止的时间
executor.setAwaitTerminationSeconds(WAIT_TERMINATE_TIME);
return executor;
}
}

面向IO的异步

面向IO的操作,是异步编程的应用场所之一。在通过IO访问数据的方式,同步编程需要主动读写数据,在读写数据的过程中还是可能会遇到阻塞;异步编程只需要I/O操作完成的通知,并不主动读写数据,而是由操作系统内核完成数据的读写。

在《Unix网络编程》第二卷中,提到了5种IO模型:

前四种io模型为同步io模型,只有异步io模型与posix定义的io相匹配。异步IO在用户进程触发I/O操作以后就立即返回,继续开始做自己的事情,而当I/O操作已经完成的时候会得到I/O完成的通知。异步IO的执行者是内核线程,内核线程将数据从内核态拷贝到用户态,所以没有阻塞。

Linux2.6以后引入了AIO,主流的IO机制可能是EPOLL,一种性能卓越且编程简单的异步IO机制,在Nginx的配置中就可以看到它的身影。

网络编程中的异步

网络编程是一种特殊的IO操作,socket 编程中同样存在着同步和异步调用。网络编程的目的是网络通信,而网络通信的传输协议无外乎那八字的四原则:

  • 组装
  • 复用
  • 纠错
  • 流控

在Python中,可以asyncio来实现网络通信中的异步编程,asyncio库包含异步IO、事件循环、协程、task等内容,事件循环是asyncio提供的核心运行机制。

从分布式系统的角度来看,消息队列提供了异步通信的能力,借助消息队列,多个模块间可以灵活的进行消息传递,这里的异步通信就是指消息生产者可以将消息放入队列中,而不等待结果返回,由消息队列负责投递消息给消费者。在系统设计中,我们可以通过消息队列来进行模块间的通信。

太多的概念了,其实都是为了试图理解“异步”这一核心概念,还是举个例子吧。

DuerOS 中的异步推送

DBP开放平台向开发者开放了技能内异步推送的机制,技能内推送意味着开发者能够在用户的会话周期内,异步调用推送接口向设备端推送相关内容或协议指令。典型的应用场景,包括银行类耗时较长的操作处理,对用户的异步通知等等。

目前DBP平台提供了两大类的异步推送,分别为文本和BOT协议。文本又分为纯文本,使用该类型将在设备端底部展示一个通知,同时内容为文本内容;另一种是TTS,设备端将用语音播报相关的TTS;BOT协议提供了更丰富的设备端内容展示的情景。

权限申请

使用服务之前需要先在DBP开放平台申请该服务的权限:

编辑技能->配置服务,在服务权限配置下可以看到“技能内异步推送”,点“申请”,申请信息会加到审核列表里,待运营人员审核通过后,服务的状态将变成“已通过”,服务的权限即申请完成。若想下掉该权限,点击“下线”即可下线服务。

使用模板

文本模板

依次点击"编辑技能->推送服务→内容模板",进入文本模板页,该页由DBP提供了部分通用的系统模板,开发者只需在调用相关接口时更改相关参数即可:

通配参数在模板里用%%包含的字符串表示,同时该页面提供了渲染模板的测试工具,填入相应的模板ID、参数的键值对,点击生成后就能得到最终渲染完的文本内容:

BOT协议模板

点击“BOT协议”导航,进入BOT协议模板列表页,这里列出了DBP当前支持使用的BOT协议模板:

如上图,目前DBP提供了AudioPlayer.Play指令模板,使用该指令时,通过推送接口将会让设备端调起AudioPlayer并播放指定的音频。

点击AudioPlayer.Play链接,进入详情页,详情页里展示了该指令支持的字段、字段类型、可选、是否可自定义以及示例等信息,推送接口将会根据这些定义项进行数据校验,开发者在使用时不要传错数据:

对于部分模板,DBP提供了可自定义的字段,可以设置自定义字段的键与类型,提交审核通过后,就可以使用了,目前支持的类型分别为STRING,INT, ARRAY, OBJECT, BOOLEAN,所填的字段都是必须传的,推送接口会校验相应的字段与类型:

DEBUG 调试

BOT协议模板未审核通过前,可以先debug,debug时需要用户绑定自己的设备SN,设备SN在设备的底部,每个技能最多只能绑定5个设备:

调用推送接口

推送接口地址为:https://xiaodu.baidu.com/saiya/v1/notification/reprompt,method为POST,需要设置Content-Type为application/json:

$ curl --location --request POST 'https://xiaodu.baidu.com/saiya/v1/notification/reprompt'
--header 'Authorization: bearer {{apiAccessToken}}'
--header 'Content-Type: application/json'
--data-raw '{
"dialogRequestId": {{dialogRequestId}},
"notificationType": "plainText",
"templateId": "1",
"debug": 1,
"templateParams": {
"userName": "张三",
"botName": "测试技能"
}
}'

其中header里要将{{apiAccessToken}}替换成实际的apiAccessToken,该值从BOT request里获取,在context.System.apiAccessToken里。POST的body为json格式,其中:

  • dialogRequestId: 必选,从request里获取request.dialogRequestId
  • notificationType: 必选,值分别为,plainText-纯文本类型,将在有屏设备底部以通知方式呈现;plainTts-将以语音方式播报;botProtocol-BOT协议类型
  • templateId: 必选,当notificationType为plainText和plainTts时,这个值就是内容模板里的模板ID值,为数值;当为botProtocol时,就是BOT协议里的指令名称,如AudioPlayer.Play
  • debug: 可选,为1时,工作在debug模式,指令只能往指定设备推送,为0或不填时工作在线上模式
  • templateParams: 可选,当notificationType为plainText和plainTts时,内容为文本模板里参数的键值对;当为botProtocol时,值为具体的BOT协议内容。

例如,一个bot协议的推送请求如下:

curl --location --request POST 'https://xiaodu.baidu.com/saiya/v1/notification/reprompt'
--header 'Authorization: bearer {{apiAccessToken}}'
--header 'Content-Type: application/json'
--data-raw '{
"dialogRequestId": {{dialogRequestId}},
"notificationType": "botProtocol",
"templateId": "AudioPlayer.Play",
"debug": 1,
"templateParams": {
"type": "AudioPlayer.Play",
"playBehavior": "REPLACE_ALL",
"audioItem": {
"stream": {
"url": {{音频URL}},
"token": "7de36bb44852ae287028ba830565a6ef"
},
"playInfo": {
"content": {
"title": "音频测试",
"titleSubtext1": "音频"
}
}
}
}
}'

小结

许多工作和技术上的争执源自概念的混淆,技术上的概念不同于文学作品——“每个人眼中都有一个自己的哈姆雷特”。讨论问题的基础好像应该是,澄清概念和明确问题的领域边界。

异步是一个常见的概念,但在不同的场景中有着不同的含义,本文梳理一下相关内容,试图可以澄清一些。

原文:聊聊“异步”_我相信......-CSDN博客

异步通信在生活中的例子_聊聊工作中经常遇到的“异步”,你掌握了多少相关推荐

  1. 分层结构的生活例子_分层架构中的服务层-服务层实战

    引言 服务层是在交互的两个层中间又定义了另外一个层,典型的是在表现层和业务逻辑层之间.这个中间层只是实现应用的用例的类集合. 服务和面向服务的出现,使得整个解决方案更有价值.更加成功.与表现层相比,服 ...

  2. vue 中provide的用法_聊聊Vue中provide/inject的应用详解

    众所周知,在组件式开发中,最大的痛点就在于组件之间的通信.在 Vue 中,Vue 提供了各种各样的组件通信方式,从基础的 props/$emit 到用于兄弟组件通信的 EventBus,再到用于全局数 ...

  3. axios 超时_聊聊 Vue 中 axios 的封装

    axios 是 Vue 官方推荐的一个 HTTP 库,用 axios 官方简介来介绍它,就是: Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中. 作为一 ...

  4. python索引例子_谈谈python中的索引

    最近以python为工具,取代VBA处理工作中Excel遇到的小问题,我觉得其优点:一是语言更清爽友善,因为VBA的语言一来IDE难用,语法风格不大气优雅(我个人的见解):二是,我一直怀疑Excel对 ...

  5. python遍历循环怎么理解_聊聊python中的循环遍历

    python之循环遍历 关于循环遍历大家都知道,不外乎for和while,今天我在这写点不一样的循环和遍历.在实践中有时会遇到删除列表中的元素,那么循环遍历列表删除指定元素该怎么做呢? 还是直接上代码 ...

  6. python销毁线程_聊聊 Python 中的线程

    01什么是线程? 线程是操作系统能够进行运算调度的最小单位,它隶属于进程之中,也有人叫它轻量级进程.线程自己没有系统资源,它可与同属一个进程的其它线程共享进程中的资源,同一进程中的多个线程可以并发运行 ...

  7. word敲空格文字不后退_聊聊Word中的几种缩进(中)

    一些闲言碎语 想要打破Word的二八定律何其难呀!80%的人仅使用了Word20%的功能!我见到了太多太多把Word当记事本去用的人.因为Word的门槛非常低,几分钟便能掌握一个功能,而且许多功能未免 ...

  8. java string hash变量_聊聊 Java 中 HashMap 初始化的另一种方式

    如果你接触过不同的语言,从语法和代码层面来说,Java 是一种不折不扣的"臃肿.啰嗦"的语言,从另一方面来说这种臃肿和啰嗦也体现了它严谨的一面,作为适合构建大型.复杂项目的理由之一 ...

  9. baq在聊天中啥意思_职场中的“老实人”如何实现逆袭,得到领导的重用?

    朋友说他最近很郁闷,喊我出来喝茶. 一起坐下以后,他开口便说:"我准备辞职了,你看看有什么好的坑没,给介绍个". 听到这个说法,我一时感到很惊讶. 之所以出乎意料,因为我知道我这朋 ...

最新文章

  1. 拥抱人工智能报告:中国未来就业的挑战与应对
  2. 【机器学习入门到精通系列】SVM与核函数(附程序模拟!)
  3. 关于ansible 创建目录安装redis、nginx
  4. PowerDesigner中Stereotype的创建图解
  5. mybatis 开发环境搭建
  6. Spring MVC 4快速入门Maven原型已改进
  7. 16-Flutter移动电商实战-切换后页面状态的保持AutomaticKeepAliveClientMixin
  8. 高级软件工程第四次作业:两只小熊队团队作业
  9. 科学家风采|郑纬民:任中国计算机学会理事长四年的三点回忆
  10. (王道408考研数据结构)第八章排序-第三节1:简单选择排序
  11. c语言运行VBA,C语言选择题部分模块和VBA.ppt
  12. 企业员工管理系统封面html,单页面模板
  13. 初识Java反序列化
  14. 中级经济师工商管理和人力资源哪个专业容易考一些?
  15. python---之struck.pack()和struct.unpack
  16. AFX_MODULE_STATE作用
  17. Linux如何使用find命令将查找出来的文件删除或者复制到另一个位置?
  18. 「雕爷学编程」Arduino动手做(23)——矩形脉冲发生器
  19. 【转载】国内主要的量化交易平台及链接
  20. [Work Summary] Python将PDF转换成Word文档

热门文章

  1. DevOps发展的9个趋势
  2. linux centos 编译luabind-0.9.1 动态库 静态库
  3. 无招胜有招之语言基础
  4. P8-07-23 在 GitLab 提交代码后自动触发 Jenkins 构建;使用禅道进行项目管理
  5. 【REST】REST是什么
  6. SQL查询最大值,返回整行数据
  7. Java中的垃圾回收
  8. 数据结构(2) -- 线性表的顺序表示
  9. 【解题报告】Leecode. 575. 分糖果——Leecode每日一题系列
  10. 【三种解法】剑指 Offer 06. 从尾到头打印链表【附完整可运行代码】