异步通信在生活中的例子_聊聊工作中经常遇到的“异步”,你掌握了多少
在我們編程的時候,經常會遇到一個概念——異步,諸如異步通信,異步線程,異步代碼,異步調用,異步編程等等,那么
什么是異步呢?
為什么要異步?
異步的典型場景是什么?
如何使用異步呢?
......
異步——通信?
老碼農初識異步是從單片機的串行通信開始的。串行通信,是指通信雙方按位進行,遵守時序的一種通信方式。串行通信有兩種類型,一種是同步通信,另一種就是異步通信。
同步通信的特點是要求發送時鐘和接收時鐘保持嚴格的同步,異步通信的發送端和接收端可以由各自的時鐘來控制數據的發送和接收,這兩個時鐘源彼此獨立,互不同步。異步通信中的接收方并不知道數據什么時候會到達,發送方發送的時間間隔可以不均勻,接收方是在數據的起始位和停止位的幫助下實現信息同步的。簡單的說,異步是扔出去一段數據,對方靠著內容前后所檢查到的特殊性發現了它,把這個內容存下來;而同步通信是對方在時刻等著發送方發號施令,發送方告訴對方要發送了,然后雙方一拍即合。
從通信效率來看,同步通信效率高,異步通信效率較低。但從實現方式來看,同步通信較復雜,異步通信相對簡單,計算機的接口大多是異步的。
進一步,對通信網絡而言,同步網一般是指網絡內所有電信設備的時鐘(或載波)提供同步控制信號,使它們的頻率工作在共同速率(或頻率)上的支撐網。同步網可分為準同步網和同步網兩類,由具有相同標稱頻率的不同基準時鐘互相比對的同步網稱為準同步網,由單一基準時鐘控制的稱為同步網。我國和大多數國家采用分級主從同步法,國家間采用準同步法。異步網絡不需要時間同步,可以在任何節點完成逐分組的轉發,這種分組的不可預測和不規則機制增加了網絡的阻塞率。然而,異步網絡具有同步網絡所不具備的低成本、低復雜度、高健壯性和高靈活性,通過合理設計交換的結構和協議,也可達到良好的交換性能。
關于通信網乃至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博客
總結
以上是生活随笔為你收集整理的异步通信在生活中的例子_聊聊工作中经常遇到的“异步”,你掌握了多少的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 大数据实效_全流程监督 让大数据督查取得
- 下一篇: 基金指数温度怎么算_医药冷链物流——运输