前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >网络访问优化下载

网络访问优化下载

作者头像
xiangzhihong
发布2018-01-29 15:37:56
1.1K0
发布2018-01-29 15:37:56
举报
文章被收录于专栏:向治洪向治洪

利用有效网络访问优化下载

使用无线电波(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公司。

图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秒的时间,大大的降低了电量消耗。

图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秒,这意味着可以通过预取技术或者批量上传来大幅提高效率。

通过监测数据传输的频率与每次传输的数据量,可以查看出哪些位置应该进行优化,通常的,图中显示的短小的类似钉子形状的位置,可以与附近位置的请求进行合并。

为了更好的检测出问题所在,Traffic Status API允许你使用TrafficStats.setThreadStatsTag()的方法标记数据传输发生在某个Thread里面,然后可以手动的使用tagSocket()进行标记到或者使用untagSocket()来取消标记,例如:

代码语言:javascript
复制
TrafficStats.setThreadStatsTag(0xF00D);
TrafficStats.tagSocket(outputSocket);
// Transfer data using socket
TrafficStats.untagSocket(outputSocket);

Apache的HttpClient与URLConnection库可以根据当前getThreadStatusTag()的值自动tag sockets。那些库在被长连接回收以后,仍然可以tag和untag sockets。

代码语言:javascript
复制
TrafficStats.setThreadStatsTag(0xF00D);
try {
  // Make network request using HttpClient.execute()
} finally {
  TrafficStats.clearThreadStatsTag();
}

Socket tagging 是在Android 4.0上才被支持的, 但是实际情况是仅仅会在运行Android 4.0.3 or higher的设备上才会显示.

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2014-04-14 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 利用有效网络访问优化下载
    • 无线电状态机
      • 看应用如何影响无线状态机
        • 预取数据
          • 批量传输与连接
            • 减少连接次数
              • 使用DDMS网络通信工具来识别瓶颈所在
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档