多線程這個名詞,大概在10年前剛踏入大學(xué)校園時就開始斷斷續(xù)續(xù)的聽人說起,當(dāng)時感覺他是一個神秘且強大的東西,感覺他是計算機領(lǐng)域的一個高級貨。而一路走來,到了現(xiàn)在感覺這東西其實也沒那么高高在上?,F(xiàn)實生活中,有很多普通常見的地方我們都用到了多線程的思想。比如去銀行辦理業(yè)務(wù),并不是大家排著一條隊伍等著一個一個進行,而是有多個辦理窗口在同時工作,由總的排號系統(tǒng)協(xié)調(diào)需要辦理業(yè)務(wù)的人們排隊等候,然后某個窗口有空閑的時候就會安排隊伍最前面的人到該窗口辦理。這些都跟計算機的多線程運行機制一樣,銀行就相當(dāng)于一個多線程處理器(CPU),而每個過來辦理業(yè)務(wù)的人們就好比一個一個需要處理的線程,系統(tǒng)級別的服務(wù)安排每個人到不同的分核處理器上去辦理運行自己的相關(guān)業(yè)務(wù)。不斷的有人進來,不斷的有人辦理完離開,我們計算機中的多線程其實也就是這樣。
那么為什么要用多線程呢,首先,效率高是顯而易見的,之前只有單核處理器的時候,很多系統(tǒng)就可以將一些工作劃分為多個工作片段,然后讓這些不同工作的片段交替在同一個處理器上執(zhí)行,對于用戶的表現(xiàn)就好像這些工作在同時進行。用戶體驗大大提升,當(dāng)多核處理器出現(xiàn)的時候,這種處理方式就更加完美高效,對于用戶來說也表現(xiàn)更佳,速度更快。而這只是概括性的初級原因,稍微接觸一些程序開發(fā)你就會知道,很多情況下沒有多線程,有些問題幾乎是沒有其他辦法解決的,下面我就舉幾個典型的例子。
第一個,牽扯到界面操作刷新與大量數(shù)據(jù)運算的。比如我曾經(jīng)做過的一個項目中的某個功能,音頻EQ處理功能能。大家大可不必糾結(jié)EQ處理到底是什么,其實是一個專業(yè)音頻處理中的部件,大家不用太關(guān)注,這里的EQ其實簡單來說就有三個參數(shù),根據(jù)這三個參數(shù)可以計算一條曲線,我們軟件的功能就是在界面中用戶可以設(shè)置這三個參數(shù),然后根據(jù)用戶設(shè)置的參數(shù),使用我們的EQ算法計算一條曲線并且在界面中顯示出來。需要說明一下的是,這個計算非常龐大,需要占用一定的時間和CPU工作量。而改變參數(shù)的方式有幾種,用戶可以在編輯框輸入,那么每次輸入新的參數(shù),我們就會計算一次曲線,并且刷新顯示界面。這倒是沒有問題。但是用戶還可以通過在界面中直接拖動點的方式來改變這三個參數(shù),這下麻煩了,用戶隨便拖動一下這個點,這個點可能就會被改變了10多次甚至更多,我們需要平滑的將這個拖動改變的過程呈現(xiàn)給用戶,如果拖動中的每次響應(yīng)我們都按照之前方式處理,進行一次龐大的計算,并且重新刷新界面,那么只有一個結(jié)果,用戶看到的是一卡一卡跳動的曲線,并不是平滑過渡的顯示。而用戶要是拖動的比較久的話情況會更糟糕,之前的響應(yīng)一直排隊等候處理,每次都是計算一次,然后刷新界面一次。用戶的拖動操作響應(yīng)很快,而處理很慢,就像高速運行的公路上出現(xiàn)了車禍,本來的三車道被占用了兩車道,大家只能排著隊從剩下的一個車道通過,而后面還有源源不斷的車快速的行駛過來,而出口卻只有一個,這樣就會造成堵車。而這種堵車呈現(xiàn)的用戶的結(jié)果就是界面卡頓,有可能用戶已經(jīng)拖動到了某個位置,而界面還在上個位置刷新,甚至用戶已經(jīng)結(jié)束了拖動操作有一段時間了,但是界面還在不停的跳動刷新,因為之前用戶的操作響應(yīng)還并未完成。這個時候多線程就要粉墨登場了。在這里我啟動了一個專門進行曲線計算的線程,我們暫且稱其為計算線程,主線程則仍然負責(zé)界面中的工作,主要是界面刷新顯示。計算線程每0.2秒執(zhí)行一次,每次查看公共數(shù)據(jù),也就是那三個可以改變的參數(shù)是否有變化,有變化就開始使用新的參數(shù)計算。計算完成之后通知界面刷新。這樣處理之后果然就流暢很多??赡茉谝幻胫畠?nèi)用戶拖動改變了10次數(shù)據(jù),但是我們只取中間的幾次進行計算并刷新界面,而且將計算與刷新界面分開兩個線程進行,也大大提升了效率。計算的時候界面也可以同時刷新,而刷新界面的時候,計算線程也在不停的為下次刷新準(zhǔn)備著數(shù)據(jù)。其實解決這個問題還用到了一些其他的技術(shù),比如定時處理等,但是這些都是基于多線程,沒有多線程其他的都是空談。

如上圖所示,以上例子中的EQ處理功能,在ShowMS(演出管理App)中可以查看并體會。該APP在App Store中已經(jīng)上架,大家可以直接在App?Store中搜索ShowMS下載查看,但是提醒一下,該APP只能運行在ipad上。
總結(jié)一下,只要是刷新界面的前置工作,而這個工作又需要大量時間的話那最好就啟動另外一個線程來執(zhí)行這個工作。
第二個使用到多線程的地方主要是網(wǎng)絡(luò)請求層面的東西,網(wǎng)絡(luò)這東西本來就有很多不確定因素,最直觀的就是網(wǎng)速有時候不一定穩(wěn)定,如果是無線網(wǎng)有時候也會受到干擾,而且很多情況下你也不能確定你發(fā)送請求的對方是否當(dāng)前穩(wěn)定在線,是否已經(jīng)卡死奔潰。所以基于以上種種不穩(wěn)定因素,網(wǎng)絡(luò)請求的響應(yīng)時間其實經(jīng)常差別很大,快的時候幾十毫秒就返回了甚至更快(1秒等于1000毫秒)。慢的時候?qū)Ψ奖豢ㄋ?,可能直到你設(shè)定的10秒20秒超時時間到的時候才能返回。所以這個時候我們發(fā)送網(wǎng)絡(luò)請求,并且響應(yīng)其返回的過程就不能簡單的在主線程順序執(zhí)行。需要用到多線程,比如當(dāng)你需要發(fā)送一條網(wǎng)絡(luò)請求的時候,你就啟動一個線程,在這個線程中組建報文發(fā)送然后等待其返回結(jié)果并進行處理。這樣并不會影響其他線程,最主要的是不影響主線程刷新界面,用戶不會以為你的軟件卡住了界面不能操作了,當(dāng)然還有更多的方式,比如組建和發(fā)送報文的過程是在本地進行,因為這塊處理時間其實我們是可以把控并且也較短的,所以這塊還可以在主線程進行,而將報文交于系統(tǒng)開始發(fā)送之后,我們就不在主線程處理了,單獨啟動一條線程等待該網(wǎng)絡(luò)請求返回,并且在這個線程中處理返回數(shù)據(jù)。就好像公司老板不一定任何事情都需要親力親為,他開會將重要的事情安排之后,就離開了,留下一個副總在本地監(jiān)督查看具體工作執(zhí)行,而老板就好比主線程,繼續(xù)去開展和推動其他事情順利執(zhí)行,而留下的副總就相當(dāng)于你啟動的另外一條線程。
第三種情況就是一些常運行的工作,比如保持網(wǎng)絡(luò)連接的心跳功能,定時啟動設(shè)備檢測的功能,主頁面的定時數(shù)據(jù)獲取以及界面刷新??傊枰L期運行,并且需要耗費比較多時間的工作,需要另外啟動一個線程在后臺運行。當(dāng)然耗費時間比較少也可以使用一些開發(fā)環(huán)境提供的定時器,而這種定時器在很多編譯環(huán)境中其實仍然使用的是主線程,但是看起來好像是多線程一樣,只是系統(tǒng)定了一個鬧鐘,鬧鐘一到點,系統(tǒng)就會在主線程上加載運行你定時器中設(shè)置的功能,所以如果這些功能耗費時間比較久,工作量比較大建議這種還是要酌情使用多線程處理。定時器其實相當(dāng)于一個假的輕量的多線程。
以上幾個地方只是一些比較典型的案例,其實多線程在其他很多地方也會用到。說了這么多但并未提及實質(zhì)性的技術(shù),是因為我覺得我們開發(fā)人員具備多線程思想比具備多線程技術(shù)更重要,對,多線程思想,什么時候時候我們該啟動一條線程,漂亮的將一部分工作和代碼劃分出來,并且讓程序運行的更高效穩(wěn)定,而什么時候我們又不該啟動一條線程,因為過多的濫用線程也會造成很多系統(tǒng)資源的浪費,線程間的同步與通訊也可能引入更嚴重的問題,讓程序變的更加復(fù)雜且難懂。所以這個度就較難拿捏,只有大家在不斷的實踐中去體會。而關(guān)于實現(xiàn)多線程的技術(shù),大家不要把他想的太難,接下來的章節(jié),我會具體介紹關(guān)于IOS多線程實現(xiàn)的相關(guān)技術(shù),請大家繼續(xù)關(guān)注。