閱讀214 返回首頁    go 汽車大全


網絡訪問優化下載

利用有效網絡訪問優化下載

使用無線電波(wireless radio)進行數據傳輸可能是應用最耗電的操作之一。為了降低網絡連接的電量消耗,清楚的理解連接模型(connectivity model)如何影響底層的無線通訊硬件設備,顯得尤為重要。

這節課介紹了無線電波狀態機(wireless radio state machine),並解釋了應用的連接模型(connectivity model)是如何與之交互的。進而我們會提出一些建議和方法去優化數據連接,使用預取策略(use prefetching),捆綁傳輸,最終達到降低數據傳輸的電量消耗的目的。

無線電狀態機

一個完全活動的無線電會消耗非常大的電量,因此我們需要讓它在不同的能量狀態之間切換,在非使用狀態時保存電量,在啟用時最小化延遲。

典型的3G無線電網絡狀態機包含三種能量狀態:

全功耗狀態(Full power): 當無線連接被激活時,允許設備以最大的傳輸速率進行數據傳輸。

低功耗狀態(Low power): 一種中間狀態,相當於全功耗狀態(Full power)50%左右的功耗。

空閑狀態(Standby): 最低功耗狀態,通常表示網絡連接未激活或者無需網絡連接的情況。

在低功耗或者空閑狀態時,電量消耗相對來說是較少的。順便介紹一下網絡請求的延遲機製。從low status切換到full status大約需要1.5秒,從idle status切換到full status需要2秒。為了最小化延遲,狀態機使用了一種延後過渡到更低能量狀態的機製。下圖是一個應用典型3G無線電波狀態機的定時器,出自AT&T公司。

mobile_radio_state_machine.png

圖1. 典型3G無線電波狀態機

在每一台設備上的無線狀態機,特別是相關聯的延遲時間和建立延遲的過程,都會根據無線電波的製式(2G,3G,LTE等)而改變,並且由設備本身所使用的網絡進行定義與配置。

這節課描述了一種典型的3G無線電波狀態機,數據來源於AT&T公司。這些原理經過實驗證明是通用的最好的,適用於所有無線電波。

這種方法在典型的網絡瀏覽時特別有效,利用它人們瀏覽網頁時可以避免煩人的網絡延遲。相對較低的後期處理時間同時保證了一旦一個session結束,無線電波就可以切換到一個較低的能量狀態.

不幸的是,這種方法在現代智能機比如Android上的應用效率低下,因為應用本身可以同時運行在前台(此時應特別關注如何避免延遲阻塞)和後台(此時應特別關注電量消耗)。

看應用如何影響無線狀態機

每一次新創建一個網絡連接,無線電波就切換到full power狀態。在上麵典型的3G無線電波狀態機情況下,無線電波會在傳輸數據時保持在full power的狀態,結束之後會有一個附加的5秒時間切換到low power,再之後會經過12秒進入到low energy的狀態。因此對於典型的3G設備,每一次數據傳輸的會話都會引起無線電波持續消耗大概20秒的能量。

實際上,這意味著一個app傳遞1秒鍾的unbundled data會使得無線電波持續活動18秒[18=1秒的傳輸數據+5秒切換到low power的時間+12秒切換到standby的時間]。因此每一分鍾,狀態機有18秒處於high power狀態,42秒處於low power狀態。

比較而言,同樣的應用每分鍾持續傳輸3秒bundled data時, 在high power狀態僅需8秒,在low power狀態僅需12秒。上麵第二種傳輸方式每分鍾節省了40秒的時間,大大的降低了電量消耗。

graphs.png

圖2 無線電bundled和unbundled數據傳輸對比圖

預取數據

預取(Prefetching)數據是一種減少獨立數據傳輸會話數量的有效方法。預取技術允許你通過一次連接,最大限度的下載到給定時間內單次操作所需的所有數據。

通過預先加載傳輸,可以減少下載數據所需的無線電的數量。從而不僅維持了電量,而且改善了延遲,降低了帶寬占用,減少了下載次數。

預取技術降低了在操作行為和瀏覽數據之前因等待數據下載完成而帶來的延遲,從而很好的提升了用戶體驗。然而,預取技術使用過度,不僅僅會導致電量消耗和帶寬占用快速增長,還有可能預取到一些並不需要的數據。同樣,確保應用不會因為等待預取數據而延遲啟動是非常重要的。

實際上,我們可以逐步處理數據,或者按照一定的優先級來進行數據傳輸,比如優先下載應用啟動所需要的數據。如何適度使用預取技術,取決於將要下載的數據的大小以及其將來被使用的可能性。

大概的策略就是,基於以上所述的狀態機,如果此數據在當前的用戶會話中有50%的機率被用到,那麼我們可以預取大約6秒左右的數據量(大約1-2Mb),保持這樣規模的數據量,可以滿足潛在需要使用的數據量。

一般來說,我們僅僅隻需要每隔2-5分鍾開始另一段下載保持1-5MB的數據量。根據這個原理,大數據的下載,比如視頻文件,應該每隔2-5秒開始另一段下載,這樣能有效的預取到幾分鍾預覽數據。值得注意的是,優化的下載的數據應該是bundled形式的,正如下一部分描述的那樣,批量傳輸和連接以及類似的方式基於連接類型和速度而變化,正如根據連接類型調整下載模式所討論的。

請看下麵兩個實例:

一個音樂播放器

你可以選擇預取整個專輯,但是如果用戶隻聽了第一首歌就停了下來,那麼我們就浪費了大量的帶寬和電量。

一個較好的方法是維持一首歌的緩衝區。 對於流媒體,維持一個持續的流會使得無線電一直處於激活狀態。所以我們考慮通過實時的HTTP流分段緩衝傳輸音頻流,正如以上所說的預取的方式。

一個新聞閱讀器

許多新聞閱讀器試圖在選擇目錄後隻下載標題來節省帶寬。完整的文章僅在用戶想要讀取的時候再去讀取,當用戶下滑時才會讀取更多信息。

使用這個方法,無線電波在用戶滾動標題,改變目錄,或者閱讀文章時才會被激活。但是即使這樣,當用戶在各種操作之間切換時,頻繁的能量狀態切換也會導致很大的延遲。

一個比較好的方法是在啟動時預先存取適量的數據,比如開始的時候可以預取一些新聞標題和縮略圖,至少保證主標題列表已經可以完全顯示,然後再去存取剩下的標題和縮略圖。

另一種選擇是在後台執行預先計劃,去預取所有的標題,縮略圖,文本,甚至全文圖片。這種方法存在的風險在於會消耗大量的帶寬和電量去下載一些無用的內容。所以此方法請謹慎使用。

一種解決方案是, 隻有在Wi-Fi連接狀態才去安排執行全速下載,有可能的話,設備最好是處於設備充電狀態。更詳盡的研究成果參考 根據連接類型改變下載模

批量傳輸與連接

使用典型3G無線網絡製式的時候,每一次初始化一個連接(與需要傳輸的數據量無關),都有可能導致無線電波持續花費大約20秒的電量。

一個app,若是每20秒進行一次ping server的操作,假設這個app是正在運行且對用戶可見,那麼這會導致無線電波不確定什麼時候被開啟,最終可能導致沒有傳輸任何數據,卻消耗了很大的電量。

因此,對數據進行bundle操作並且創建一個序列來存放這些bundle好的數據就顯的非常重要。操作正確的話,可以使得大量的數據集中進行發送,這樣使得無線電波的激活時間盡可能的少,同時減少大部分電量的花費。這樣做的潛在好處是盡可能在每次傳輸數據的會話中盡可能多的傳輸數據而且減少了會話的次數。

例如:新聞客戶端可以分析用戶的使用行為習慣,根據這些習慣來做決定如何獲取數據,獲取多少,什麼時候獲取等。在這個例子中,所有收集到的用戶習慣應該捆綁一起,之後再一起進行發送,而不是每次點擊的行為都去發送這個碎片數據。同時,發送這些數據不應該在下載一個全圖或者執行例行更新的時候去操作。

減少連接次數

重用已經存在的網絡連接比起重新建立一個新的連接通常來說是更有效率的。重用網絡連接同樣可以使得在擁擠不堪的網絡環境中進行更加智能的互動。當可以捆綁所有請求在一個GET裏麵的時候不要同時創建多個網絡連接或者把多個GET請求進行串聯。

例如,可以一起請求所有文章的情況下,不要根據多個欄目進行多次請求。無線電波會在等待接受返回信息或者timeout信息之前保持激活狀態,所以如果不需要的連接請立即關閉而不是等待他們timeout。

之前我們說過,如果關閉一個連接過早,會導致後麵再次請求時重新建立一個在Server與Client之間的連接,而我們說過要盡量避免建立重複的連接,那麼有個有效的折中辦法是不要立即關閉,而是在timeout之前關閉(即稍微晚點卻又不至於timeout)。

使用DDMS網絡通信工具來識別瓶頸所在

The Android DDMS (Dalvik Debug Monitor Server) 包含了一個查看網絡使用詳情的選項卡來跟蹤應用的網絡請求。使用這個工具,可以監測應用是在何時,如何傳輸數據的,從而進行代碼優化。下圖顯示了傳輸少量的網絡模型,可以看到每次差不多相隔15秒,這意味著可以通過預取技術或者批量上傳來大幅提高效率。


DDMS.png

圖3. DDMS 網絡跟蹤選項卡


通過監測數據傳輸的頻率與每次傳輸的數據量,可以查看出哪些位置應該進行優化,通常的,圖中顯示的短小的類似釘子形狀的位置,可以與附近位置的請求進行合並。

為了更好的檢測出問題所在,Traffic Status API允許你使用TrafficStats.setThreadStatsTag()的方法標記數據傳輸發生在某個Thread裏麵,然後可以手動的使用tagSocket()進行標記到或者使用untagSocket()來取消標記,例如:

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

Apache的HttpClient與URLConnection庫可以根據當前getThreadStatusTag()的值自動tag sockets。那些庫在被長連接回收以後,仍然可以tag和untag sockets。

TrafficStats.setThreadStatsTag(0xF00D);
try {
  // Make network request using HttpClient.execute()
} finally {
  TrafficStats.clearThreadStatsTag();
}

Socket tagging 是在Android 4.0上才被支持的, 但是實際情況是僅僅會在運行Android 4.0.3 or higher的設備上才會顯示.

最後更新:2017-04-03 20:19:25

  上一篇:go JDBC PreparedStatement 批量查詢 in 的實現 方案
  下一篇:go 無法定位程序輸入點 CreateUri 於動態鏈接庫 urlmon.dll 上。