iOS高效能程式設計 之效能指標
一、定義效能
從技術視角嚴格來說,效能是非常模糊的術語。當一個人說“這是個高效能的應用”時,其實我們無從判斷他說的是什麼。他是說應用消耗的記憶體少?應用節約了網路流量?還是說應用使用起來非常流暢?總而言之,高效能有著多重的含義和豐富的解釋方式。
效能可以和我們實際開發中的多個要點關聯起來。(需要測量和監控的)效能指標是其中的一個關注點,(實際上收集資料的)測量是另一個關注點。
二、效能指標
效能指標是面向使用者的各種屬性。每個屬性可能是一個或多個可測量工程引數的一個要素。
1 記憶體
記憶體涉及執行應用所需的 RAM最小值,以及應用消耗的記憶體平均值和峰值。最小記憶體值
會嚴重限制硬體,而更高的記憶體平均值和峰值意味著更多的後臺應用會被強制關閉。
同時還要確保沒有洩漏記憶體。隨時間流逝而持續增長的記憶體消耗意味著,應用很可能會因為記憶體不足的異常而崩潰。
2 電量消耗
在編寫高效能程式碼時,電量消耗是一個需要重點處理的重要因素。就執行時間和 CPU資源的利用而言,我們不僅要實現高效的資料結構和演算法,
還需要考慮其他的因素。如果某個應用是個電池黑洞,那麼一定不會有人喜歡它。
電量消耗不僅僅與計算 CPU週期有關,還包括高效地使用硬體。除了要實現電量消耗最
3 初始化時間
應用在啟動時應執行剛好夠用的任務以完成初始化,從而滿足使用者的使用需求。執行這些任務消耗的時間就是應用的初始化時間。
剛好夠用是一個開放式用語——正確的平衡點取決於應用的需要。
在首次使用應用時建立物件並進行初始化是一個合理的選擇,例如,直到需要使用物件時才建立物件。這種方式被稱為惰性初始化。
這是一種很好的策略,但也要考慮不能讓使用者總是在執行後續任務時等待。
下面列舉了你可能想在應用初始化階段執行的一些動作,排名不分先後。
• 檢查使用者是否已經登入。
• 如果使用者已經登入,儘可能地載入之前的狀態。
• 連線伺服器以拉取最新的變更。
• 檢查應用是否由某個深層連結喚起。如果是,還需要載入深層連結相應的UI和狀態。
• 檢查是否存在應用上次啟動時掛起的任務,需要時恢復它們。
• 初始化後續需要使用的物件和執行緒池。
• 初始化依賴項(如物件關係對映、崩潰報告系統和快取)。
這個列表可能會迅速變長,並且很難決定哪些條目一定要在啟動時執行,哪些可以延後幾毫秒再執行。
4 執行速度
一旦啟動應用,使用者總是希望它可以儘可能快地工作。一切必要的處理都應該在儘可能短的時間內完成。
例如,在照片應用中,使用者通常希望看到調整亮度或對比度等簡單效果的實時預覽效果。因此,相應的處理需要在幾毫秒內完成。
這可能需要本地計算的並行處理技術或能夠將複雜任務分發到伺服器。
5 響應速度
每個應用都應該快速地響應使用者互動。在應用中所做的一切優化和權衡最終都應該體現在響應速度上。
App Store 中有許多應用可以完成相似或相關的任務。這為使用者提供了很大的選擇空間,而使用者基本都會選擇響應最快的應用。
6 本地儲存
針對任何在伺服器上儲存資料或通過外部來源重新整理資料的應用,開發人員應該對本地儲存的使用有所規劃,以便應用具備離線瀏覽的能力。
例如,使用者都希望郵件應用能夠在無網路或裝置離線的情況下瀏覽歷史郵件。
同樣,新聞應用也應該可以在離線模式下顯示最近更新的新聞,並標記出每條新聞是否已讀。
然而,從本地儲存中載入和同步資料應該迅速、便捷。這不僅需要選擇要在本地快取的數據和要優化的資料結構,還需要提供一系列的配置選項並確定資料同步的頻率。
如果你的應用使用了本地儲存,那麼請提供一個清除資料的選項。遺憾的是,市場上的大部分應用都沒有提供此選項。更讓人煩惱的是,一些應用竟然會消耗數百兆的存 儲空間。
使用者會頻繁地解除安裝這些應用來回收本地儲存。這會導致糟糕的使用者體驗,從而威脅應用的成功。
一定要向終端使用者提供清空本地快取的選項。如果使用者開啟了 iCloud的備份功能,那麼應用的資料將會消耗使用者的儲存限額,請謹慎使用。
7 互操作性
使用者可能會使用多個應用來完成某個任務,這就需要這些應用直接提供互操作的能力。
例如,一個相簿可能需要一個幻燈片應用來實現最佳的瀏覽體驗,但需要另一個應用來編輯照片。
其中瀏覽照片的應用要能夠將照片傳送到編輯器,並接收編輯後的圖片。
iOS 為實現應用間的互操作和資料共享提供了多種機制,其中包括UIActivityViewController、深層連結、MultipeerConnectivity框架,等等。
為深層連結定義良好的URL結構與編寫優異的程式碼來解析 URL同樣重要。
類似地,使用共享對話方塊共享資料時,精確識別用於分享的資料非常重要,同時,在處理不同資料來源傳入的資料時還要注意安全隱患。
如果某個應用向附近裝置共享資料時需要花費很長時間準備資料,那麼使用者體驗就會非常糟糕。
8 網路環境
移動裝置會在不同網路環境下使用。為了確保能夠提供最好的使用者體驗,你的應用應當適應各種網路條件:
• 高頻寬穩定網路
• 低頻寬穩定網路
• 高頻寬不穩定網路
• 低頻寬不穩定網路
• 無網路為使用者提供進度指示或錯誤資訊是相對合理的方式,無盡的等待或崩潰則讓人無法接受。
應用會採取向終端使用者傳遞資訊的不同方式:比如音訊收聽應用有的應用顯示了已經緩衝的資訊流大小,以此告訴終端使用者還需要等待多久才可以播放音樂。
有的應用僅提供了不明確的進度條,這在非流式應用中是更為常見的樣式。
9 頻寬
人們會在不同的網路條件下使用自己的移動裝置,網速從每秒數千位元組到每秒數十兆位元組。
因此,頻寬的優化使用是定義應用質量的另一個關鍵引數。此外,在高頻寬網路下執行一個基於低頻寬網路開發的應用可能會產生完全不同的結果。
為提高效能所做的設計並非每次都能如願,也可能會導致相反的效果。
10 資料重新整理
即使沒有提供離線瀏覽能力,你仍然可以從伺服器端週期性地重新整理資料。
重新整理的頻率和每次傳輸的資料量將決定資料傳輸的總量。如果傳輸的位元組數過大,那使用者必然會快速耗盡自己的流量計劃。
當流量消耗大到一定程度時,你的應用很可能會流失使用者。
在 iOS 6.x或更低版本中,在後臺執行的應用不能重新整理資料。
從 iOS 7開始,應用可以在後臺週期性地重新整理資料。對於線上聊天類應用,持久的 HTTP連線或原生 TCP 連線可能會非常有用。
11 多使用者支援
家庭成員間可能會共享移動裝置,或者一個使用者可能會擁有同一應用的多個賬號。
例如,兄弟姐妹間可能會共享一個 iPad來玩遊戲。
再比如,家庭成員可能會在旅遊時配置一個設備來查收全家人的電子郵件,以減少漫遊費用,尤其是在境外旅遊時。類似地,一個人也可能會配置多個電子郵件賬號。
是否支援多個併發使用者取決於產品的需要。一旦決定提供此類功能,請參考以下準則。
• 新增新使用者應儘可能高效。
• 在不同使用者之間更新應儘可能高效。
• 在不同使用者之間切換應儘可能高效。
• 使用者資料的界限應該簡潔且沒有bug。
12 單點登入
如果你已經建立了多個允許或需要登入的應用,那麼支援單點登入(single sign-on,SSO)是非常棒的選擇。
如果使用者登入了一個應用,只需要點選一次,就可以登入到其他的應用中。
這個過程不僅需要支援跨應用的資料共享,還需要分享狀態、跨應用同步等。例如,如果使用者登出了其中某個應用,則通過 SSO登入的所有其他應用也應能登出掉。
此外,應用之間的同步應該是安全的 13 安全
安全對移動應用來說是最重要的,因為敏感資訊可能會在應用間共享。因此,對所有通訊以及本地資料和共享資料進行加密就顯得尤為重要了。
實現安全需要更多的計算、記憶體和儲存,但這與最大化執行速度、最小化記憶體和儲存使用的目標相沖突。
因此,你需要在安全和其他因素之間進行權衡。
引入多個安全層會影響效能,並對使用者體驗造成可感知的負面影響。如何設定安全的基線需要參考對使用者群體的統計分析。
此外,硬體在其中扮演了重要的角色:選擇會因為不同裝置的計算能力而有所不同。
14 崩潰
應用可能會而且確實會崩潰。過度優化會導致崩潰。同樣,使用原始 C程式碼也可能會導致崩潰。
高效能的應用不僅應儘可能地避免崩潰,還應該在崩潰發生時優雅地恢復,尤其是在進行某個操作的過程中發生崩潰時。
三、應用效能分析
1 取樣
顧名思義,取樣(或基於探測點的效能分析)是指以一定的週期間隔採集狀態,這通常需要藉助工具。“iOS高效能程式設計之埋點與分析” 將介紹這些工具。
由於不會干擾應用的執行,因此取樣可以很好地提供應用的全景圖。取樣的不足之處在於它不能返回 100%精確的細節。
如果取樣的頻率是 10毫秒,那麼你就無法得知在探測點之間的 9.999毫秒內發生了什麼。
取樣可以作為初始的效能調研手段,並可用於跟蹤 CPU和記憶體的使用情況。
2 埋點
通過修改程式碼,記錄細節資訊的埋點能夠提供比取樣更加精確的結果。
你既可以在關鍵部分主動埋點,也可以在效能分析或處理使用者反饋時有針對性地埋點,以便解決問題。“iOS高效能程式設計之埋點與分析”中將深入討論這一過程。
因為埋點需要注入額外程式碼,所以它一定會影響應用的效能,對記憶體或速度(或同時對二者)造成損害。