1. 程式人生 > >不耗電傳輸資料(一):高效網路連線下載優化

不耗電傳輸資料(一):高效網路連線下載優化

Contents

高效網路連線下載優化... 1

無線狀態機... 1

應用如何影響無線狀態機... 2

預取資料... 2

批量傳輸和連線... 3

降低連線數量... 4

用網路分析器定位問題... 4

 

高效網絡連線下載優化

用無線網路傳輸資料是耗電量最大的操作之一。為了降低網路活動的耗電量,理解連線模型對下層無線硬體的影響很重要。

這一課會介紹無線網路狀態機並解釋了你的應用是如何與之互動的。提供了一些方法,減少資料連線,用預取,繫結傳輸,來降低資料傳出的耗電量。

線狀態機

全面啟動的無線網路耗電量巨大,當不用的時候為了省點它進入不同能量狀態,同時又要降低啟動所花費的時間。

典型的3G網路訊號狀態機有三個能量狀態:

全能量:當有一個活動的連結時,允許裝置以最高速率傳輸資料。

低能量:中間狀態,大約消耗全能量電量的50%。

待機:最低電量消耗狀態,在這個狀態沒有活動的連線或沒有請求。

儘管地能量和待機省很多電,但也引入了重大網路延時。從地能量狀態到全能量狀態約需要1.5秒,從待機狀態進入全能量需要2秒多。

為了減少延遲,狀態機從全能量態進入低能量態引入一個延遲。下圖用AT&T演示了一個3G網路

每臺裝置的訊號狀態機的延遲時間和恢復時間跟當前執行的網路技術有關(2G,3G,LTE,etc.),並通過裝置正在使用的運營商定義和配置。

這節課基於AT&T的資料描述了一個由代表性的典型3G網路的狀態機。但是,這一基本原則和結果適用於所有無線網路。

對於典型的瀏覽網頁,這項策略非常重要。他防止使用者瀏覽網頁時那些不受歡迎的延遲。相對來說一個比較小的休眠時間也保證了當一個會話結束時,無線網路能進入一個低耗電的狀態。

不幸的是,這個策略影響了執行在Android系統上的應用效率,在Android系統中,應用即執行在前臺(延遲會影響效率),也在後臺執行(應該優化電池使用)。

用如何影響無線狀態機

每次進建立一個新的連線,狀態機就進入全能量態。在上面的典型的3G網路狀態機例子中,資料傳輸時,會持續保持在全能量態,外加5秒鐘休眠時間,然後是12秒鐘低能量態時間。所以典型的3G裝置,一個會話大約持續20秒要耗電。

在實際使用中,如果一個應用不繫結傳輸資料,並每18秒傳送1秒資料,就會導致無線網路一直執行,也就是剛要進入待機模式時,又恢復全能量模式了。也就是1分鐘裡,大約18秒鐘時全能量態,42秒鐘是低能量態。

比較而言,如果應用每分鐘繫結傳輸3秒資料,那麼全能量態只會持續8秒,低能量態12秒。

後一個例子是的網路在每分鐘有40秒待機時間,大大降低耗電量。

取資料

資料預取對於降低獨立資料傳輸會話數量效果顯著。資料預取允許你在一個單獨的連結中滿負荷的一次性下載你可能在一段時間內所需要的所有資料。

預取同時改進了使用者體驗,降低了操作和瀏覽資料之前等待下載完成這部分延遲。

但是,如果用的太頻繁,預取可能會有增加耗電量和頻寬使用的危險,同時也消耗流量,因為有可能預取了很多無用資料。確保預取不影響應用啟動也很重要,因為有可能應用要等預取結束才能啟動。在實際實現中,可能意味著逐步處理資料,或者建立一個基於優先順序的連續傳輸,應用啟動所需的資料先傳出,先處理。

如何預取決定於資料大小和後續被用到的可能性。一個粗略的指導,基於上面的狀態機,對於當前使用者會話,假如資料被用到的機率是50%,同時考慮到下載到無用資料的消耗和預取省下的電量,你可以下載約6秒鐘(1到2Mb)資料。

一般來說,預取一次,大約1到5兆位元組,就只需要每2到5分鐘再次啟動下載,就比較好。

按照這個原則,像視訊檔案這樣的大量下載,就應該定期的(每2到5分鐘)大塊下載,高效的預取下面幾秒很有可能被瀏覽到的資料。

注意進一步下載應該被繫結,像下面一段所說的,批量傳輸和連線,而且這些近似值應該根據傳輸型別和速度的不同而調整。

看一個例子:

音樂播放器

你可以選擇預取整個專輯,但是使用者可以聽完一首就不聽了,這樣你浪費了大量的下載和電量。

更好的選擇是留一個緩衝區,緩衝正在播放和將要播放的兩首曲子。對於流音樂,不要一直維護一個持續的流,這會導致連線網路狀態機一直處在高能耗狀態,考慮用HTTP直播流,批量傳輸資料,模擬上面的預取的操作。

新聞閱讀器

很多新聞類的應用為了降低頻寬消耗,在使用者選擇一個新聞型別後,只下載標題,當用戶點進去再去下載具體文章,如果使用者只是滑動到某個新聞,只下載縮略文。

用這種策略,使用者瀏覽標題,切換新聞型別,察看文章時,網路就要一直保持啟用狀態。不僅如此,當用戶切換新聞型別和察看具體文章時,狀態機的切換會帶來大量延遲。

更好的策略是在啟動時預取一定數量的資料,首先是第一組新聞標題和縮略文,確保降低應用啟動延時,然後繼續下載剩下的新聞標題和縮略文和主要標題列表內的文章的文字。

另一個策略就是預取每個標題,縮略文和文章文字甚至圖片,一般在後臺週期性排程。但是這種策略有可能導致消耗大量頻寬和電量,下載了很多不需要的東西,所以要慎重使用。

另一個方案就是當連線WiFi時全下載,有可能還需要連線著外接電源。

批量傳輸和連線

每次你初始化一個連線,不管傳輸多少資料,都意味著引起無限網路20秒鐘的耗電,假設是一個典型的3G網路。

如果你的應用每20秒ping一下網路,只是為了確認應用還在執行並且對使用者可見,會導致無線網路一直耗電,進而導致大量耗電,儘管沒傳輸資料。

基於此,建立一個待傳輸佇列繫結資料傳輸很重要,如此,你可以把鄰近的網路請求同時執行,讓無線網路儘量降低耗電時間。

背後的邏輯就是在一個會話中儘量多傳輸資料,而不要總是啟動會話。

這意味著你要把能夠容忍等待的資料請求先放佇列,用預排程更新和預取對時間敏感的傳輸先執行。相似的,你的排程更新和定期預取也負責那些待傳輸佇列的排程。

還是用預取的例子。

假設新聞應用使用上文預取的方法。新聞閱讀器收集分析資料,瞭解使用者的閱讀模式,歸類最受歡迎的文章。為了重新整理新聞,每小時更新。為了省頻寬,不下載所有文章的圖片,只預取縮略文,和最受歡迎的文章的圖片。

在這個例子中,應用收集的所有分析資訊都應該繫結併入佇列下載,而不是以收集完就下載。該結果繫結傳送應該在一個圖片下載完或者每小時更新完成後。

任何時間敏感或使用者請求的傳輸,比如圖片下載,都應該優先定期排程。計劃的更新應該在使用者請求資料的同時執行,並把下次更新的時間設成當前時間加上間隔。這個策略把常規的更新和一個時間敏感的又必須執行的圖片下載繫結起來。

降低連線數量

一般來說,重用已有會話比建立新會話省電。重用連線也能幫助網路更智慧的處理擁堵等其他網路資料傳輸問題。

不要同時建立多個會話下載資料,也不要用一系列的GET取資料,而應該儘量在一個GET裡獲得所有資料。

例如,對每個新聞文章只用一個連線和響應就比多個新聞型別用多次請求效率高。無線網路需要一直保持啟用來傳輸與客戶端和伺服器超時相關的結束/結束通知包,所以當連線不再需要時,把它關掉而不是等待超時。

即便如此,關掉一個連線它就不能複用了,增加了建立一個新連線的費用。一個比較有用的折中辦法就是不要立即關掉連線,但是在超時之前關閉它。

用網絡分析器定位問題

用網路分析器跟蹤你的應用的網路訪問。你可以檢測到應用什麼時候,如何傳輸了資料,用來優化程式碼。

下圖顯示了應用每隔大約15秒鐘就取資料,也就是說通過預取和繫結的優化,能大大提高效率。

通過檢測資料傳輸頻率,每次傳輸的資料量,你可以知道那些地方可以改進。一般來說,一要找的是那些小細尖,看能否延遲請求;或者讓後續傳輸提前。總之就是繫結傳送。

為了更好的識別傳輸的小細尖,Traffic Stats API允許你用TrafficStats.setThreadStatsTag()給一個執行緒中的傳輸新增標籤,然後用TrafficStats.tagSocket()和TrafficStats.untagSocket()對執行緒中Socket新增和刪除標籤。例如:

TrafficStats.setThreadStatsTag(0xF00D)
TrafficStats.tagSocket(outputSocket)
// Transfer data using socket
TrafficStats.untagSocket(outputSocket)

HttpURLConnection庫基於TrafficStats.getThreadStatTag()自動給Socket打標籤。這個庫也通過keep-alive池自動給Socket打和去除標籤。

private class IdentifyTransferSpikeTask extends AsyncTask<String, Void, String> {

    @Override

    protected void onPreExecute() {

      TrafficStats.setThreadStatsTag(0xF00D);

    }



    @Override

    protected String doInBackground(String... urls) {

        try {

            // Make network request using HttpURLConnection.connect()

        }

    }



    @Override

    protected void onPostExecute(String result) {

        TrafficStats.clearThreadStatsTag();

   }

}

Socket標籤在Android4.0中就支援了,但是時事統計僅在Android4.0.3及以上版本支援。