本文是投稿文章,作者:yishuiliunian
首先這是一個很宏大的題目,我也只能窺其一斑。只說說自己的一些淺見和反思。因為之前有一段時間,在面對說要技術方案優化的時候,自己也有過一段不知所措的時期。後來才開始慢慢覺得自己找到點門道了,這片文章也算是自己的一個總結吧。
什麼是優化
首先我們先破題,來談談“優化”這個事情。通常情況下,我們說到優化的時候,往往會伴隨著對之前系統的吐槽。或是不好用,或是性能低,或是用起來很麻煩。巴拉巴拉。是的,當我們對原先的系統有槽點的時候,我們會談到“優化”。而“優化”的前提也是,之前已經有過一個東西存在,而且真對目前的場景應景不再適合。這個是有需要對原有系統進行調整,以滿足當前的場景與需求。那麼所謂優化即是:對原有系統進行有目的的改造。
好吧,這聽起來雖然說了什麼,但其實什麼都沒說。因為這是一句大實話。
but,我們仔細分析一下,我們要進行優化必須能夠:
對原有系統的問題有所了解
了解目前場景和需求
有目的性的改造原有系統
我們來說一個我們通常會遇到的例子,也是在面試的時候會遇到的問題–“UItableView的性能優化”。其實每次有人問我這個問題,我內心都有千萬只“草泥馬”奔騰而過。沒有具體的問題場景,只單單跑出來這樣一個問題。是可以和他扯什麼圖片內存緩存了,避免圓角的使用了,預渲染,預加載了之類的東西。但是這些東西,真的對於在解決他們TableView卡頓的問題有效嗎,不見得。套用《安娜卡列尼娜》一句話:
流暢的UItableView都是相似的,不流暢的UItableView各有各的不幸。
好了,吐槽到此為止。吐槽的目的是為了說明一點,你要進行優化,必須有一個特定的場景。在一個受限的范圍內進行優化,因為這樣目的是可控的。漫無邊際的優化,和別人基於方法論的建議之類的東西,不一定對當前的問題有幫助。
比如,之前我們在做的一個社交類的App中,首頁使用了UItableView,老板說怎麼用著這麼卡頓。然後我們就開始了“優化”。
首先,我們知道我們要優化的是第一個tab的tableview的滑動效率的問題。那總得有個監控的指標吧。對於程序猿來說,感覺這個不卡了,或者感覺這個卡,這個東西太模糊了。無法衡量啊。所以一定要量化。對於界面來講就是大家常說的FPS,每秒幀率。於是我們測量了一下幀率,平均下來是25FPS。ou my god!的確是有點卡。
然後我們知道對於ios來說如果能達到60FPS,那界面絕對不會有卡頓的感覺了。而很少有應用能達到這個水准。那麼我們給自己設置了一個目標45FPS。btw,這個目標只是個階段性目標。
好了下面的過程,就是朝著這個目標前進了。當然我們知道,造成FPS較低的原因,一般都是主線程做了太多的事情,導致幀率降低。這只是個大方向。而對我們來講,我們需要精准的知道,主線程都做了些什麼事情,導致幀率降低。
首先,我們發現的是,讀取圖片IO的過程發生在了主線程。IO過程一般是比較耗時的,於是我們像把該過程移到了後台線程中處理。發現幀率能夠提高到33FPS,這還不夠啊。革命尚未完成,同志仍需努力。
之後的過程中,我們把布局預處理,還有圓角,數據預加載之類的事情做上去之後,終於基本達到45。階段性目標完成。
好了這是一個優化的例子:始於發現問題,止於目標達成。而重要的是其過程,描述問題!!!!
分析問題 (定性or定量)
其實,我一直比較堅信一句話:當你能夠准確的描述一個問題的時候,你到解決問題就沒剩幾步了。比如剛才說的卡頓的問題,我們當時是這麼描述的:圖片讀取發生了主線程,主線程中有一部分CPU片段用於文件讀取和圖片解碼,造成主線程阻塞,從而導致幀率下降。當描述到這裡的時候,解決方案就比較顯而易見了,挪呗。搞到其他線程中之行。把主線程空出來。
而上面的這個描述還只是一個定性的描述分析。只是闡述了現象。雖然能夠解決了一個問題,但是對整體問題的貢獻有多大,也未可知。所以我們可以當時完全可以這樣描述:我們圖片緩存在文件系統的平均大小是1MB,其讀取時間為10.7ms,圖片格式為jpeg,解碼一個1M的圖片耗時是60ms,而我們知道60FPS,每幀給主線程用來處理任務的CPU時間為17.7S,也就說這個地方占用了大量CPU時間片來處理圖片讀與解碼操作,從而造成了CPU阻塞,造成幀率沒有達到60ms。
當我們使用定量的描述的時候,我們能夠比較精確的知道,一個小問題,對於大問題來說到底意味著什麼。而定量分析的方案中,當然包含了很多更多的細節信息,尤其是數據信息。這些也正是定量分析的優勢所在。BUT,定量分析是一個非常耗時耗力的事情,你要拿到這麼多的數據,你勢必要付出很多時間,在采集這些數據上面。對於app開發來講,除非公司給了足夠的資源(尤其是時間),你才能像個研究者一樣去采集這些數據,一般情況是,大概都會止步到定性分析這一步。其實這也是看具體問題而定了。
不過無論你是使用定性分析的方式還是定量分析的方式。我們的目標是為了找到能夠准確表述問題的方式,並且定位問題,以求找到解決方案。而為了達到這個目的一般情況下我們可以使用兩種方式:
你的編程功底和對iOS的了解程度都很深,那麼完全可以從一些原理性的事情上去分析。我們稱之為:邏輯分析法。
或許你的編程功底很深,或許很淺,或許你嘗試分析而沒有結果。那麼可以使用改改代碼試試的方法了。我們稱之為:實驗法。
邏輯分析法, 原理性分析
哈哈,套用馬哲的一句話:事物是普遍聯系的。既然是普遍聯系的,不說必然存在因果,那麼通過一定的邏輯分析。是可以找到他們之間的一些蛛絲馬跡的關聯的。這些關聯或許可以解釋一些什麼。比如剛才卡頓的問題:原理就是主線程CPU被消耗過多,無法及時處理UI任務導致的。這只是一個例子。
我們進行邏輯分析的目的,是為了找到我們的某些代碼和問題之間的因果性聯系。就是說,我們能夠明確知道造成UI卡頓的問題,就是因為IO的問題之類。這個話題說起來,比較深邃了。其中絕大部分實踐的方法可以從《數理邏輯》這本書中找到。不過這是本講數學的書,咱們得稍微換下腦子,把其中的定理,在編程中應用一下。因為我也只是意會了其中的某些東西,講出來還沒有那麼功底。就只能麻煩各位自己去琢磨了。:)
實驗法,Assume-Action-Response-Test-Assume
我稱這個過稱為AARTA。這是一個一直往復的過程,在分析的過程中,你得一次次的重復這個過程來找到真正問題的所在。其實,這個方法比較常應用在改BUG這個場景上。其實如果從廣義上講,按照上面咱們對技術優化的定義,改bug也算是一種優化。只不過這個場景比價特殊而已。當無法准確的分析原理,或者當前程序的復雜性過高(低內聚高耦合)已經超出人腦的計算能力范圍的時候,那麼就可以“猜”了。
(1)假設 assume
根據以往的經驗來,設定一個和問題域相關的假設。比如UI卡頓的問題,你懷疑是不是因為圖片的問題呢。那麼現在就假設是圖片的問題!
(2) 嘗試進行修改 action
既然假設是圖片的問題,那麼就把UIImageView從Cell上刪掉吧。
(3)看程序的反饋 Response
重新運行一遍程序,看一下程序運行的效果。FPS是否有所改善,而且改善的幅度有多大。
(4)Test
根據,程序的反饋和我們預先設定的目標來判斷一下,當前改動是否滿足了我們設計的目標。如果有,那麼你大概就找到了問題的一個原因。如果沒有那麼進行下一步。
(5) 重新提出假設 Assume
既然不是圖片的問題,那麼會不會是其他事情上耗費了CPU呢。比如布局樣式的計算。那麼重新假設是局部樣式的問題。在執行(2)過程。
所謂實驗,即是大膽假設,小心取證,如此往復,以求終解。
監控
上面只是進行了一些方法論的探討。但是有一件事情,是若要優化一定要做的。那就是“監控”。
監控是個非常重要的東西。
監控是個非常重要的東西。
監控是個非常重要的東西。
重要的事情說三遍。尤其是對於運行在生產環境的程序。這就像是一個體檢,你得實時掌控程序的運行情況,知道問題出在了哪裡,甚至有些時候知道:哎呀,出問題了。沒有監控,程序一旦上線之後,就像脫缰的野馬,跑到哪裡,做了什麼,你就是一頭忙然了。突然有一天,老板說有人反饋咱們的app經常崩潰,當你沒有crash監控,這個你都不知道從哪裡查起。
而且,監控也是優化的數據來源。他能夠通過數據的指標來非常直觀的告訴你,程序哪裡有問題,你優化之後,效果是怎樣的。現在網上有很多這方面的服務提供出來,比如bugly之類的,甚至有些是APM(application performance manager),直接監控到程序的運行狀態和性能。google一下,能搜出不少來。可以酌情,應用在自己開發的app中。
總結
說了半天,總結一下。優化是在可控的范圍內有目的性的對現有程序的修改。一般可以使用邏輯分析法和實驗法來定位、分析、描述問題。或者定性或者定量。無論哪種,要想優化,你得先建立起對自己app運行的監控體系。
歡迎關注iOS開發公共賬號 iOS開發知識。