Android效能優化篇之計算效能優化

不會Android發表於1970-01-01

介紹

Android中的Java程式碼會需要經過編譯優化再執行的過程。程式碼的不同寫法會影響到Java編譯器的優化效率。例如for迴圈的不同寫法就會對編譯器優化這段程式碼產生不同的效率,當程式中包含大量這種可優化的程式碼的時候,運算效能就會出現問題。想要知道如何優化程式碼的運算效能就需要知道程式碼在硬體層的執行差異。

1.低效率函式

如果你寫了一段程式碼,它的執行效率比想象中的要差很多。我們需要知道有哪些因素有可能影響到這段程式碼的執行效率。例如:比較兩個float數值大小的執行時間是int數值的4倍左右。這是因為CPU的運算架構導致的,如下圖所示:

Android效能優化篇之計算效能優化

雖然現代的CPU架構得到了很大的提升,也許並不存在上面所示的那麼大的差異,但是這個例子說明了程式碼寫法上的差異會對運算效能產生很大的影響。

通常來說有兩類執行效率差的情況:第1種是相對執行時間長的方法,我們可以很輕鬆的找到這些方法並做一定的優化。第2種是執行時間短,但是執行頻次很高的方法,因為執行次數多,累積效應下就會對效能產生很大的影響。

修復這些細節效率問題,需要使用Android SDK提供的工具,進行仔細的測量,然後再進行微調修復。

2.Traceview

前面已經講過,這裡就不在介紹了。

3.計算效能優化

(1).批處理與快取

為了提升運算效能,這裡介紹2個非常重要的技術:批處理與快取
是在真正執行運算操作之前對資料進行批量預處理,例如你需要有這樣一個方法,它的作用是查詢某個值是否存在與於一堆資料中。假設一個前提,我們會先對資料做排序,然後使用二分查詢法來判斷值是否存在。我們先看第一種情況,下圖中存在著多次重複的排序操作。

Android效能優化篇之計算效能優化

在上面的那種寫法下,如果資料的量級並不大的話,應該還可以接受,可是如果資料集非常大,就會有嚴重的效率問題。那麼我們看下改進的寫法,把排序的操作打包繫結只執行一次:

Android效能優化篇之計算效能優化

上面就是批處理的一種示例:把重複的操作拎出來,打包只執行一次。
快取相對比較簡單,就是把經常處理的資料先快取起來,使用時直接獲取,但是要注意,當程式碼執行完畢需要回收(當然也可以使用weakRefrence)。

(2).主執行緒阻塞

為了確保應用程式的高效能,每項功能都應該儘可能高效地執行。但是這些功能的執行時間以及它們在程式碼中所處的位置也很重要,當你首次啟動一個Android應用程式時,朱執行執行緒就已經建立了,主執行緒非常重要,因為它負責執行你的程式碼,並在合適的檢視位置傳送事件和執行繪圖功能。這些前面我們已經講過,基本上來說,主執行緒是應用程式所在的執行緒,有時候,主執行緒也稱為UI執行緒。例如,如果你觸控螢幕上的按鈕,UI執行緒將會傳送一個觸控事件給檢視,檢視將按鈕狀態設定為已按下設定,然後向事件佇列傳送一個有效請求,然後UI執行緒處理此請求,並通知按鈕將其本身繪製為已按下狀態。如果你有任何觸控事件的處理程式碼塊,將會線上程中執行,這些觸控處理所用的時間越長,執行緒的執行時間就會越長,在繪圖功能執行完之前,檢視將會更新顯示狀態,讓使用者能夠看到其狀態,這裡需要記住的是,輸入處理程式碼與渲染和更新程式碼,共享這個執行緒的處理週期時間。

Android效能優化篇之計算效能優化

這意味著,在觸控事件處理,網路訪問或資料庫查詢等計算週期時間,UI不會更新繪圖,在簡單的情況下,渲染週期可能會延誤16毫秒左右,而讓使用者感到延遲。但是,如果你暫停UI執行緒渲染超過5秒,使用者將會看到“應用程式未響應”對話方塊,並詢問使用者是否會想要關閉你的應用程式,這樣可能導致使用者停止使用。那你如何解決這個問題,你要找出不需要在主執行緒上執行的功能,也就是說,不需要等它們完成之後,才能執行繪圖。你應該將這個功能轉移到一個單獨的獨立執行緒,這個執行緒不會阻止UI執行緒。例如,如果你按一下提交按鈕,以完成一個訂單,然後編寫和傳送確認郵件,

Android效能優化篇之計算效能優化

這可以在單獨的執行緒上完成。Android有系列很好用的API,能夠簡化這些工作。

(3).非同步任務

給耗時操作建立非同步任務,比如網路請求,圖片處理等等,任務完成通知主執行緒。

(4).容器效能

前面我們講過,一些型別的硬體可能會造成程式執行速度較慢,還記得那個浮點分支問題嗎?對於今天的硬體來說,這已經不是問題。但是有一些問題還是需要引起注意,比如說,你所使用的程式語言的基本元素的效率,以排序等基本演算法為例,現在,有很多的排序演算法,對於不同的情況,它們各有優劣,例如,當元素數量少於一千或在大型已排序列表中尋找一個物件時,快速排序法通常比起氣泡排序法更快。一般情況下,最好的方法是二分查詢演算法,但是,當在未排陣列中尋找物件時情況變得完全不同,不同於比較每一個物件以查詢你想要的值。你可以使用一個雜湊函式來立即找到它,這是現代電腦科學和資料結構方面的基本知識。

幸運的是,現代程式語言像Java等,為你提供了這些容器和演算法,因此你不再需要自己反覆地編寫Murmur3雜湊函式和快速排序演算法。但是你需要知道另外一些事情,在我多年的程式設計生涯中,一個經常會影響專案效能的問題,是由於這些語言提供的容器物件的效能所引起的。這聽起來不可思議!Java提供一個向量類的實現,你可以任意push、pop,新增和取消物件,為了獲得這種靈活性,它在內部使用鏈式列表結構,這種結構具有一系列獨特的效能特性,在你操作這種列表時,它的速度超級快,但是,當你在其他位置進行插入或刪除時,它會消耗大量的時間。我要說的是,底層系統提供的這些容器並不會考慮,你的程式將會如何實際使用它們,James Sutherland發表了一系列的基準測試報告,他認為,我們需要注意效能與功能之間的一些差異。例如,他發現Hashtable比HashMap大約快22%,具體視你如何使用這些容器而有所不同,我們需要思考的是,你是否曾經分析過你在程式碼中使用的容器類。你是否堅信,你在程式碼中使用的容器的實際執行速度絕對是最快的。一個好訊息是,你可以使用Android中的MPI來剖析這些容器的效能。

Android效能優化篇之計算效能優化

(5).資料結構

建立應用時,容器中不恰當的資料結構所造成的效能問題,為此我們可以使用Android SDK中的工具,來識別不恰當資料結構帶來的效能問題。

來源:https://juejin.im/post/5c4eb83cf265da613572ef56

相關文章