今天讀了一本計算機底層的書,書中詳細(xì)闡述了同步與異步在系統(tǒng)底層方面的處理方法。這篇文章就來討論一下什么是同步,什么是異步,它們在編程中到底意味著什么。要想寫出高性能高并發(fā)的代碼,這是很關(guān)鍵的基礎(chǔ)。
相信很多同學(xué)在開始接觸到同步異步這兩個詞的時候大腦一片懵逼,沒錯,這兩個看上去很像實際上也很像的兩個詞,曾經(jīng)也讓本人深度困擾,以至于夜不能寐。這兩個詞具體的含義到底是什么呢?
先來看一個咱們身邊常見的場景:
美好的一天從打卡開始,現(xiàn)在起你化身為
苦逼程序員
假設(shè)現(xiàn)在老板安排給你一個十分緊急的開發(fā)任務(wù),讓你下班前必須整出來(萬惡的資本主義)。為了確保能夠完成任務(wù),老板就坐在你旁邊看著。
你心里肯定一萬頭羊駝奔騰而過:“***,這得多閑,干嘛盯著老子,你就不能去干別的?我還怎么摸魚”
老板仿佛看透你的小心思:“我就在這等著,你寫完前我哪兒都不去,別墨跡抓緊整。”
在上面這個例子中,老板交代給你任務(wù)后什么都不做一直等待直到你完成這就是同步的形式。
第二天老板又分配給你新的任務(wù):“小伙子能力真不錯,不用多久你就可以升職加薪、當(dāng)上總經(jīng)理、出任CEO、迎娶白富美、走上人生巔峰了。不要激動,來,先把今天這個任務(wù)完成,不著急,寫完告訴我一聲就行。”
老板說完就回去刷抖音了,而你經(jīng)過四五個小時的努力摸魚后,簡簡單單就碼完了:“老板,我寫完了,你來瞅瞅。”
這個例子中老板安排完以后就干別的事情了,而你寫完了告訴老板任務(wù)完成,這種就屬于異步的概念。
異步相對于同步最明顯的不同就是你工作的時候老板在刷劇,這兩件事情同時發(fā)生,因此從理論上講異步的效率要高于同步,對大多數(shù)場景而言是這樣的。
so,so,so!果真遇到在身后盯著寫代碼的老板,三十六計走為上策!
下面這個場景用來理解同步異步更為鮮明
打電話vs發(fā)郵件
作為苦逼程序員不能只會埋頭搬磚,工作中總得與客戶交流,最常用的方式就是打電報。。。啊不,是打電話。
通常我們打電話都是一個人說另一個人聽,對方講話的時候我方需要等待,等對方講完再接著說,而且每一步都依賴之前的講話。這里的重點是產(chǎn)生了等待,不可避免地等待,這種方式就是同步的特點。
作為搬磚碼農(nóng),另外一種比較常用的方式就是發(fā)郵件,尤其是在公司內(nèi)部。沒有人為了等你的郵件什么都不做,他可以摸摸魚,充下電,上個廁所等等。同樣的你發(fā)完郵件也不需要一直等著對方的回復(fù),這期間可以做其他有意義的事情。
在這種方式中,寫郵件和收件人摸魚這兩件事情同時發(fā)生著,雙方都不需要等待,兩件事情也不存在依賴,這就是異步的方式。
編程中的同步
現(xiàn)在回到編程的主題,上面場景展示了生活中的同步異步的意義,那么在程序開發(fā)中又該怎樣理解呢?
一般情況下函數(shù)的調(diào)用都是這樣的
/**JAVAscript */
function A( ){
//等待函數(shù)b完成
function B( )
//繼續(xù)后面的運行
}
函數(shù)A調(diào)用函數(shù)B,那么在B完成前A都不會執(zhí)行后續(xù)的代碼,就像這樣:
從上圖看到B執(zhí)行期間A什么都不能做,這就是同步。
下面這段Node代碼就是采用同步的方式執(zhí)行磁盤文件讀取,屬于阻塞式I/O
/**JavaScript */
import { readFileSync } from 'fs';
readFileSync('<directory>');//程序暫停運行,等待I/O返回數(shù)據(jù)
//文件讀取完成后繼續(xù)運行
同步編程對程序員是最好理解的,一步完成再做下一步,但代價就是在某些場景(例如I/O操作)下這種方式的效率不夠高效,因為任務(wù)沒法同時進行。
編程中的異步
有同步就有異步,在理解了前面的內(nèi)容后相信很快就能掌握異步的要領(lǐng)。
一般來說在程序開發(fā)中,一些耗時比較高的任務(wù)都是采用異步的方式,例如磁盤讀寫,網(wǎng)絡(luò)數(shù)據(jù)收發(fā),數(shù)據(jù)庫命令的執(zhí)行等。同樣以磁盤文件讀取為例,使用異步函數(shù)即使文件還沒有讀取完畢后面的代碼也能執(zhí)行。
/**javascript */
import { readFile } from 'fs';
readFile('<directory>', callback);//readFile函數(shù)立即返回
//不會阻塞程序的執(zhí)行
//某個時間點文件讀取完成后執(zhí)行callback回調(diào)
異步的重點在于調(diào)用函數(shù)后接下來的程序可以繼續(xù)和文件讀取同時執(zhí)行,這就是高效之處。
然而,異步執(zhí)行對程序員來說是一種負(fù)擔(dān),無論在閱讀還是編寫上都不容易理解。
有的同學(xué)可能會問,同步的情況下可以得到函數(shù)的結(jié)果繼續(xù)執(zhí)行,那么異步的時候又怎么知道函數(shù)執(zhí)行完成了呢?
這里一分為二:
- 不需要關(guān)心結(jié)果,執(zhí)行就ok
- 需要結(jié)果進行更多的操作
第一種無需討論,比較簡單。
第二種情況通常有兩種方式,一種是通知機制,任務(wù)完成后發(fā)送信號通知上一級,例如linux的signal方式。還有一種就是回調(diào),就是我們常說的callback。
最后需要注意的是,并非所有的情況下異步就一定比同步高效,還要結(jié)合具體的業(yè)務(wù)或者I/O復(fù)雜程度來分析。但是不管何時何地,同步意味著雙方要相互等待,相互依賴,二異步則意味著雙方相互獨立,各行其道。希望這篇文章對大家理解這兩個重要的概念有所幫助。






