線程和同步異步的知識,在我們剛踏入程序這一行業(yè)的時候就開始接觸了。
但是由于I/O(磁盤讀寫,網(wǎng)絡(luò)通信)這種耗時的操作,各個語言都有完整的封裝方法,我們并不用去了解其異步過程也能完成大部分功能。所以多數(shù)人在工作一兩年之后,仍然無法理清他們的關(guān)系。
不過它對于我們優(yōu)化代碼,了解底層不可或缺,現(xiàn)在我來盤點一下他們的聯(lián)系和概念。
一.核與線程的關(guān)系
我們平時經(jīng)常會聽到8核、16核處理器,那這里的核與線程有什么關(guān)系呢?單核代表一個線程么?
單核可以有多個線程,只是它的多線程通過分時來實現(xiàn),即把時間分成片,每片處理一個線程,所有的線程循環(huán)處理。所以對于單核系統(tǒng)而言,開多少個線程都無法提高程序的運行效率。
而多核可以同時實現(xiàn)多線程。比如雙核系統(tǒng)開兩個線程,運行效率將會翻倍。但并不代表效率可以無限提升,多線程個數(shù)等于核的個數(shù)時,效率達到最高。
比較另類的是,之前Intel有過16核32線程的機器,它的原理是超線程技術(shù)使一個核心能模擬2個邏輯核心,但據(jù)說并不能真正達到兩個核的水平。
打個形象的比喻:(每種動作代表一個線程)
單核單線程:一個人喝完酒,然后抽煙,最后吃燒鴨
單核多線程:一個人喝一口酒,抽一口煙,吃一口烤鴨,同時進行
多喝多線程:三個人,一個人喝酒,一個人抽煙,一個人吃烤鴨,互不干擾
二.同步異步、阻塞非阻塞
首先,我們先來談一下同步異步的概念,我查過很多資料,眾說紛紜,每個版本的講法都不一樣,出入很大。但其實了解這些概念是為了讓我們更加明確整個底層運作方式,所以我挑了一個比較鮮明的概念供大家參考。
(我們iOS平時說到的同步大意和這里的同步阻塞對等,異步與異步非阻塞對等,但是由于js中存在比較重要的同步非阻塞,所以我在這里拆開來講)
1、同步(sync):
發(fā)出一個功能調(diào)用時,在沒有得到結(jié)果之前,該調(diào)用就不返回。
2、異步(async):
與同步相對,調(diào)用在發(fā)出之后,這個調(diào)用就直接返回了,所以沒有返回結(jié)果。當這個調(diào)用完成后,一般通過狀態(tài)、通知和回調(diào)來通知調(diào)用者。對于異步調(diào)用,調(diào)用的返回并不受調(diào)用者控制。
對于通知調(diào)用者的三種方式,具體如下:
狀態(tài):即監(jiān)聽被調(diào)用者的狀態(tài)(輪詢),調(diào)用者需要每隔一定時間檢查一次,效率會很低。
通知:當被調(diào)用者執(zhí)行完成后,發(fā)出通知告知調(diào)用者,無需消耗太多性能。
回調(diào):與通知類似,當被調(diào)用者執(zhí)行完成后,會調(diào)用調(diào)用者提供的回調(diào)函數(shù)。
3、阻塞(block):
阻塞調(diào)用是指調(diào)用結(jié)果返回(或者收到通知)之前,當前線程會被掛起,即不繼續(xù)執(zhí)行后續(xù)操作。
簡單來說,等前一件做完了才能做下一件事。
4、非阻塞(non-block):
非阻塞調(diào)用指在不能立刻得到結(jié)果之前,該調(diào)用不會阻塞當前線程。
總結(jié):所以所謂同步異步,是對于被調(diào)用者而言的;而阻塞非阻塞,則是對調(diào)用者而言的。
和剛才一樣,打個比喻加深理解:
1、同步阻塞:你打電話給114查路線,在不掛斷的情況下,客服幫你查了十分鐘之后告訴你,期間你一直在接聽電話。
2、同步非阻塞:你打電話給114查路線,在不掛斷的情況下,客服幫你查了十分鐘之后告訴你,你期間吃了個??(打電話沒有影響你做其他事,顯示運用中也很難遇到)。
3、異步非阻塞:你打電話給114查路線,客服說查好之后打給你,這期間你可以做任何事。
4、異步阻塞:你打電話給114查路線,客服說查好之后打給你,但這期間你什么都沒做,等到回復(fù)電話之后,再繼續(xù)下一步動作。(是不是很傻)現(xiàn)實運用中,異步阻塞是沒有意義的!
三.線程與同步異步的關(guān)系
單線程可以異步操作么?當然可以。比如延遲方法,就是典型的異步。
但是單線程異步和多線程異步還是有區(qū)別的,因為單線程異步操作在通知調(diào)用者之前,是沒有跑任何的代碼的,因為沒有任何的線程提供給它。
其實由于各方概念的差異,也可以說單線程不能進行異步操作,所謂延遲方法,不過是過一段時間之后,把執(zhí)行函數(shù)加入主隊列之中,兩種說法都存在。
老規(guī)矩,打比方(這里的同步異步代表同步阻塞和異步非阻塞)
1、單線程同步:甲先搬了一塊磚,回頭又搬了另一塊磚
2、多線程同步:甲先搬了一塊磚,乙又搬了一塊磚(要用到線程間的同步機制)
3、多線程異步:甲乙同時各搬了一塊磚
四.js的坑,既然名義上是單線程的,卻為何能進行真正意義上異步操作
nodeJS編程模式:http://www.cnblogs.com/wwicked/articles/4770416.html??
知乎詳細鏈接:https://www.zhihu.com/question/20866267?
JS的單線程是指一個瀏覽器進程中只有一個JS的執(zhí)行線程,同一時刻內(nèi)只會有一段代碼在執(zhí)行(你可以使用IE的標簽式瀏覽試試看效果,這時打開的多個頁面使用的都是同一個JS執(zhí)行線程,如果其中一個頁面在執(zhí)行一個運算量較大的function時,其他窗口的JS就會停止工作)。
而異步機制是瀏覽器的兩個或以上常駐線程共同完成的,例如異步請求是由兩個常駐線程:JS執(zhí)行線程和事件觸發(fā)線程共同完成的,JS的執(zhí)行線程發(fā)起異步請求(這時瀏覽器會開一條新的HTTP請求線程來執(zhí)行請求,這時JS的任務(wù)已完成,繼續(xù)執(zhí)行線程隊列中剩下的其他任務(wù)),然后在未來的某一時刻事件觸發(fā)線程監(jiān)視到之前的發(fā)起的HTTP請求已完成,它就會把完成事件插入到JS執(zhí)行隊列的尾部等待JS處理。又例如定時觸發(fā)(settimeout和setinterval)是由瀏覽器的定時器線程執(zhí)行的定時計數(shù),然后在定時時間把定時處理函數(shù)的執(zhí)行請求插入到JS執(zhí)行隊列的尾端(所以用這兩個函數(shù)的時候,實際的執(zhí)行時間是大于或等于指定時間的,不保證能準確定時的)。
所以,所謂的JS的單線程和異步更多的應(yīng)該是屬于瀏覽器的行為,他們之間沒有沖突,更不是同一種事物,沒有什么區(qū)別不區(qū)別的。
五.ios的多線程問題
做iOS 的應(yīng)該都有一個體會,總覺得block是異步的,其實這是錯誤的理解。
block的線程和它的實現(xiàn)方法處的線程一致,所以我們在調(diào)用時,可以檢查一下它的實現(xiàn)代碼。
我們平時經(jīng)常討論的同步問題多發(fā)生在多線程環(huán)境中的數(shù)據(jù)共享問題,當多個線程同時操作一個對象時,會出現(xiàn)意想不到的bug,所以這時應(yīng)該加上線程鎖。
這篇文章總結(jié)了多篇博客,但卻沒有完全照抄,加入了很多自己的理解,希望大家多多支持。