在這篇文章中我們來討論一下到底什么是同步根竿,什么是異步陵像,以及在編程中這兩個概念到底意味著什么,這些是進一步掌握高性能寇壳、高并發(fā)技術(shù)的基礎(chǔ),因此非常關(guān)鍵妻怎。
相信很多同學(xué)遇到同步異步這兩個詞的時候大腦瞬間就像紅綠燈失靈的十字路口一樣陷入一片懵逼的狀態(tài):
是的壳炎,這兩個看上去很像實際上也很像的詞匯給博主造成過很大的困擾,這兩個詞背后所代表的含義到底是什么呢逼侦?
我們先從工作場景講起匿辩。
苦逼程序員
假設(shè)現(xiàn)在老板分配給了你一個很緊急并且很重要的任務(wù),讓你下班前必須寫完(萬惡的資本主義)榛丢。為了督促進度铲球,老板搬了個椅子坐在一邊盯著你寫代碼。
你心里肯定已經(jīng)罵上了“WTF晰赞,你有這么閑嗎稼病?盯著老子选侨,你就不能去干點其他事情嗎?”
老板仿佛接收到了你的腦電波一樣:“我就在這等著然走,你寫完前我哪也不去援制,廁所也不去”
這個例子中老板交給你任務(wù)后就一直等待什么都不做直到你寫完,這個場景就是所謂的同步芍瑞。
第二天晨仑,老板又交給了你一項任務(wù)。
不過這次就沒那么著急啦拆檬,這次老板輕描淡寫“小伙子可以啊洪己,不錯不錯,你再努力干一年竟贯,明年我就財務(wù)自由了答捕,今天的這個任務(wù)不著急,你寫完告訴我一聲就行”澄耍。
這次老板沒有盯著你寫代碼而是轉(zhuǎn)身刷視頻去了噪珊,你寫完后簡單的和老板報告了一聲“我寫完了”。
這個例子老板交代完任務(wù)就去忙其它事情齐莲,你完成任務(wù)后簡單的告訴老板任務(wù)完成痢站,這就是所謂的異步。
值得注意的是选酗,在異步這種場景下重點是在你寫代碼的同時老板在自己刷劇阵难,這兩件事在同時進行,因此這就是為什么一般來說異步比同步高效的本質(zhì)所在芒填,不管同步異步應(yīng)用在什么場景下呜叫。
因此,我們可以看到同步這個詞往往和任務(wù)的“依賴”殿衰、“關(guān)聯(lián)”朱庆、“等待”等關(guān)鍵詞相關(guān),而異步往往和任務(wù)的“不依賴”闷祥,“無關(guān)聯(lián)”娱颊,“無需等待”,“同時發(fā)生”等關(guān)鍵詞相關(guān)凯砍。
By the way箱硕,如果遇到一個在身后盯著你寫代碼的老板,三十六計走為上策悟衩。
打電話與發(fā)郵件
作為一名苦逼的程序員是不能只顧埋頭搬磚的剧罩,平時工作中的溝通免除不了,其中一種高效的溝通方式是吵架座泳。惠昔。幕与。啊不,是電話舰罚。
通常打電話時都是一個人在說另一個人聽纽门,一個人在說的時候另一個人等待,等另一個人說完后再接著說营罢,因此在這個場景中你可以看到赏陵,“依賴”、“關(guān)聯(lián)”饲漾、“等待”這些關(guān)鍵詞出現(xiàn)了蝙搔,因此打電話這種溝通方式就是所謂的同步。
另一種碼農(nóng)常用的溝通方式是郵件考传。
郵件是另一種必不可少溝通方式吃型,因為沒有人傻等著你寫郵件什么都不做,因此你可以慢慢悠悠的寫僚楞,當(dāng)你在寫郵件時收件人可以去做一些像摸摸魚啊勤晚、上個廁所、和同時抱怨一下為什么十一假期不放兩周之類有意義的事情泉褐。
同時當(dāng)你寫完郵件發(fā)出去后也不需要干巴巴的等著對方什么都不做赐写,你也可以做一些像摸魚之類這樣有意義的事情。
在這里膜赃,你寫郵件別人摸魚挺邀,這兩件事又在同時進行,收件人和發(fā)件人都不需要相互等待跳座,發(fā)件人寫完郵件的時候簡單的點個發(fā)送就可以了端铛,收件人收到后就可以閱讀啦,收件人和發(fā)件人不需要相互依賴疲眷、不需要相互等待禾蚕。
你看,在這個場景下“不依賴”狂丝,“無關(guān)聯(lián)”夕膀,“無需等待”這些關(guān)鍵詞就出現(xiàn)了,因此郵件這種溝通方式就是異步的美侦。
同步調(diào)用
現(xiàn)在終于回到編程的主題啦。
既然現(xiàn)在我們已經(jīng)理解了同步與異步在各種場景下的意義(I hope so)魂奥,那么對于程序員來說該怎樣理解同步與異步呢菠剩?
我們先說同步調(diào)用,這是程序員最熟悉的場景耻煤。
一般的函數(shù)調(diào)用都是同步的具壮,就像這樣:
funcA() {
// 等待函數(shù)funcB執(zhí)行完成
funcB();
// 繼續(xù)接下來的流程
}
funcA調(diào)用funcB准颓,那么在funcB執(zhí)行完前,funcA中的后續(xù)代碼都不會被執(zhí)行棺妓,也就是說funcA必須等待funcB執(zhí)行完成攘已,就像這樣:
從上圖中我們可以看到,在funcB運行期間funcA什么都做不了怜跑,這就是典型的同步样勃。
注意,一般來說性芬,像這種同步調(diào)用峡眶,funcA和funcB是運行在同一個線程中的,這是最為常見的情況植锉。
但值得注意的是辫樱,即使運行在兩個不能線程中的函數(shù)也可以進行同步調(diào)用,像我們進行IO操作時實際上底層是通過系統(tǒng)調(diào)用(關(guān)于系統(tǒng)調(diào)用請參考《程序員應(yīng)如何理解系統(tǒng)調(diào)用》)的方式向操作系統(tǒng)發(fā)出請求的俊庇,比如磁盤文件讀仁ㄊ睢:
read(file, buf);
這就是我們在《讀取文件時,程序經(jīng)歷了什么》中描述的阻塞式I/O辉饱,在read函數(shù)返回前程序是無法繼續(xù)向前推進的
read(file, buf);
// 程序暫停運行搬男,
// 等待文件讀取完成后繼續(xù)運行
如圖所示:
只有當(dāng)read函數(shù)返回后程序才可以被繼續(xù)執(zhí)行。
當(dāng)然鞋囊,這也是同步調(diào)用止后,但是和上面的同步調(diào)用不同的是,函數(shù)和被調(diào)函數(shù)運行在不同的線程中溜腐。
因此我們可以得出結(jié)論译株,同步調(diào)用和函數(shù)與被調(diào)函數(shù)是否運行在同一個線程是沒有關(guān)系的。
在這里我們還要再次強調(diào)挺益,同步方式下函數(shù)和被調(diào)函數(shù)無法同時進行歉糜。
同步編程對程序員來說是最自然最容易理解的。
但容易理解的代價就是在一些場景下望众,注意匪补,是在某些場景不是所有場景哦,同步并不是高效的烂翰,因為任務(wù)沒有辦法同時進行夯缺。
接下來我們看異步調(diào)用。
異步調(diào)用
有同步調(diào)用就有異步調(diào)用甘耿。
關(guān)于重要的異步調(diào)用踊兜,關(guān)注公眾號“碼農(nóng)的荒島求生”并回復(fù)“async”你就知道了。
同步 vs 異步
我們以常見的Web服務(wù)來舉例說明這一問題佳恬。
一般來說Web Server接收到用戶請求后會有一些典型的處理邏輯捏境,最常見的就是數(shù)據(jù)庫查詢(當(dāng)然于游,你也可以把這里的數(shù)據(jù)庫查詢換成其它I/O操作,比如磁盤讀取垫言、網(wǎng)絡(luò)通信等)贰剥,在這里我們假定處理一次用戶請求需要經(jīng)過步驟A、B筷频、C然后讀取數(shù)據(jù)庫蚌成,數(shù)據(jù)庫讀取完成后需要經(jīng)過步驟D、E截驮、F笑陈,就像這樣:
# 處理一次用戶請求需要經(jīng)過的步驟:
A;
B;
C;
數(shù)據(jù)庫讀取;
D;
E葵袭;
F涵妥;
其中步驟A、B坡锡、C和D蓬网、E、F不需要任何I/O鹉勒,也就是說這六個步驟不需要讀取文件帆锋、網(wǎng)絡(luò)通信等,涉及到I/O操作的只有數(shù)據(jù)庫查詢這一步禽额。
一般來說這樣的Web Server有兩個典型的線程:主線程和數(shù)據(jù)庫處理線程锯厢,注意,這討論的只是典型的場景脯倒,具體業(yè)務(wù)實際上可會有差別实辑,但這并不影響我們用兩個線程來說明問題。
首先我們來看下最簡單的實現(xiàn)方式藻丢,也就是同步剪撬。
這種方式最為自然也最為容易理解:
// 主線程
main_thread() {
A;
B;
C;
發(fā)送數(shù)據(jù)庫查詢請求;
D;
E;
F;
}
// 數(shù)據(jù)庫線程
DataBase_thread() {
while(1) {
數(shù)據(jù)庫讀取;
}
}
這就是最為典型的同步方法,主線程在發(fā)出數(shù)據(jù)庫查詢請求后就會被阻塞而暫停運行悠反,直到數(shù)據(jù)庫查詢完畢后面的D残黑、E、F才可以繼續(xù)運行斋否,就像這樣:
從圖中我們可以看到梨水,主線程中會有“空隙”,這個空隙就是主線程的“休閑時光”茵臭,主線程在這段休閑時光中需要等待數(shù)據(jù)庫查詢完成才能繼續(xù)后續(xù)處理流程冰木。
在這里主線程就好比監(jiān)工的老板,數(shù)據(jù)庫線程就好比苦逼搬磚的程序員,在搬完磚前老板什么都不做只是緊緊的盯著你踊沸,等你搬完磚后才去忙其它事情。
顯然社证,高效的程序員是不能容忍主線程偷懶的逼龟。
是時候祭出大殺器了,這是什么大殺器呢追葡,關(guān)于這個問題的答案關(guān)注公眾號“碼農(nóng)的荒島求生”并回復(fù)“回調(diào)”二字你就知道答案了腺律。
總結(jié)
在這篇文章中我們從各種場景分析了同步與異步這兩個概念,但是不管在什么場景下宜肉,同步往往意味著雙方要相互等待匀钧、相互依賴,而異步意味著雙方相互獨立谬返、各行其是之斯。希望本篇能對大家理解這兩個重要的概念有所幫助。