[译文]关于移动Web性能的5个神话
译者前言
这篇文章(http://www.sencha.com/blog/5-myths-about-mobile-web-performance/)由Sencha的CEO Michael Mullany所写,主要是回应早前的一篇引起较多关于移动Web性能讨论的文章“Why mobile web apps are slow”(原文,译文),作者的主要观点是“Why mobile web apps are slow”文中给出的数据虽然基本正确,但是对数据的解读却存在误导的成分,并且只考量了JavaScript的性能,而对移动应用来说更关键的Graphics性能并没有被考量在内。并且移动应用性能的提升不仅仅会得益于浏览器提升JavaScript的性能,还会得益于更高程度的GPU加速渲染,多线程并行化处理等等。
译文
我们最近听到了一些在不断重复的关于移动HTML性能的神话,但是这并不完全准确。就像那些流传已久的都市传说一样,它们听起来似乎有理有据,让人信服。但是这些神话是基于不正确的前提,对于原生应用和Web应用的软件堆栈之间的关系的概念是错误的,只是一些因为曲解了数据而推导出的漫无目的的观点。
神话#1:移动Web性能主要是由CPU主导的JavaScript性能所决定的
真相:大部分Web性能是由浏览器对渲染流水线的优化,DOM操作的速度和使用GPU加速的程度来决定的。更快的JavaScript性能的确不错,但它很少会成为性能的瓶颈。
神话#2:依赖CPU的JavaScript性能仅仅因为硬件的提升才变得更快(aka 摩尔定律)
真相:在过去4年里面50%以上的JavsScript性能的提升是得益于软件上的优化,而不是硬件上的提升。甚至单线程的JavaScript性能还在不断提升,更不用说现在很多应用开发者通过使用Web Workers来利用多线程提升性能。
神话 #3:移动浏览器最近的性能优化已经基本停滞,未来也没有更多上升的空间
真相:每一个移动浏览器都在一些特定的领域比起其它浏览器在性能上有10倍-40倍的提高。Surface的SVG性能比iPhone高30倍。而iPhone的DOM操作性能是Surface的10倍。所以对每个浏览器来说,仅仅做到向其它浏览器表现优秀的领域看齐,就有很多性能提升的空间。
神话 #4:移动应用很难再从未来的硬件性能提升中受益
真相:在过去三年里,每一次硬件更新换代都会带来JavaScript性能的飞跃。不但浏览器的单线程性能仍然在不断提升,并且还会因为更快的GPU速度,更快的内存带宽,和通过多线程并行化处理更充分地利用多核CPU来不断提升性能。越来越多的浏览器已经开始更多地利用并行化来减轻主线程的负担,比如说:Firefox使用了单独的混合线程;Chrome并行化处理HTML解析;还有IE把JavaScript的JIT编译放到了其它线程。
神话 #5:JavaScript的垃圾收集对移动应用来说是性能杀手
真相:这种说法曾经是正确的,不过现在的状况已经不太一样。Chrome在2011年的Chrome 17引入了增量垃圾收集机制。Firefox去年也实现了同样的特性。这个特性将每次GC暂停的时间从200ms降到了10ms —— 相当于丢掉一帧 vs 一个可以明显感知的停顿。避免垃圾收集事件的确可以显著提升性能,但是只有你还在使用桌面Web开发模式或者在一个老旧的浏览器上运行,垃圾收集才会成为性能杀手。以我们在Fastbook(一个Facebook HTML5应用的克隆)使用的关键技术为例,通过建立一个DOM节点的对象池来回收不再使用的DOM对象并循环使用,我们成功避免了创建新对象的开销,同时也避免了因为删除旧对象而导致GC。浏览器的确很有可能提供了一个性能非常糟糕的垃圾收集器(比如说旧的IE),但这并不是支持垃圾收集的语言比如JavaScript(或者Java)的天生的无法克服的缺陷。
OK:关键要素
首先,让我们回顾一下最基本的概念。从5万英尺的高度往下看,浏览器本身是构建于操作系统之上的一个丰富和复杂的抽象层。而Web应用混合运用标记语言,JavaScript脚本语言和样式表,使用这个抽象层来创建应用的体验。这个抽象层本身需要额外的性能开销,而开销的多少很大程度决定于你使用抽象层的哪一部分。抽象层的某些部分更快是因为它们离操作系统的系统调用或者某些系统库的调用更近(比如说Canvas2D on MacOS)。另外一些部分会比较慢是因为它们无法直接映射到底层的操作系统,并且它们天生就十分复杂(DOM树操作,JavaScript对象属性访问的原型链遍历)。
很少有移动应用是计算密集型的:没有谁会试图在iPhone上计算DNA序列。大多数应用有着一个合理的响应模型。用户执行一个操作,然后应用会马上回应一个30fps或者更高帧率的视觉动画,然后在几百毫秒之内完成任务。只要应用满足上面的要求,没有人会在乎应用基于的抽象层距离最底层的硅晶圆之间到底有多远。从这点来说,单纯地比较原生应用的抽象层和Web应用的抽象层意义并不大。
对于Sencha来说,我们知道一个优秀的开发者使用移动Web技术和基于一个现代的Web框架比如Sencha Touch,是可以创建出优秀的应用体验的,它运行的足够快,满足用户的期待。并且过去3年的移动性能飞速提升的趋势也使我们深受鼓舞。我们很乐意跟您在接下来的文章里分享一些相关的数据。
但是我们的本意并不是说移动Web应用能够运行的和原生应用一样快,或者它们能够在性能上能够与桌面Web应用相媲美。这不是真实的。移动设备的硬件性能比起桌面设备要慢5倍到10倍:CPU性能比较低,缓存层次结构过于扁平,缺少多级缓存的支持,网络链接的延迟也很高。并且任何软件抽象层本身(比如浏览器)都需要付出额外的开销。其实这不仅仅是Web应用开发者的问题。iOS原生应用的开发者一样可以告诉你,当iOS CoreGraphics在第一款视网膜iPad上性能很低的时候,这使得他们相当一部分人不得不抛弃CoreGraphics而直接使用OpenGL。
进一步追溯神话的真相
通过过去三年持续对Sencha Touch在数据驱动应用中的使用进行性能优化的经历,我们可以很自信的说,我们很少会被最原始的JavaScript性能所困扰。仅仅是在构建Sencha Touch布局系统时,因为Android 2.x的JavaScript性能太差,使得我们改用了Flexbox。
更多时候,我们碰到的问题是DOM操作太慢,浏览器渲染引擎性能比较差和垃圾事件堆积过多无法及时处理。而这些局限基本上都是因为浏览器的架构设计者和开发者造成的,跟JavaScript语言和JavaScript引擎本身并没有本质的联系。举个例子来说,有一次我们和浏览器开发者一起优化浏览器性能,我们最终在某个特定操作上(颜色属性的改变)获得了40倍的性能提高,而这之前是我们的滚动列表实现的性能瓶颈,而类似的例子还有很多。
在iOS和Android上的JavaScript性能
虽然我们说过JavaScript性能其实对于移动设备来说并不是那么重要,但是我们还是希望可以推翻它并没有得到改善的神话。下图是SunSpider测试(越低越好)在iOS上过去4年的得分(按照硬件版本和OS版本划分)。(很幸运,SunSpider是一个广泛被应用的测试,所以我们很容易就在网上找到旧的iOS设备的测试成绩)。2009年的时候,当时运行iOS3的iPhone 3GS得分是15,000 —— 非常的糟糕,跟当时的桌面浏览器的300-600的得分相差30倍左右。
http://cdn.sencha.io/img/20130730-5-myths-html5/5-html5-myths-1.png
然而,如果你把iPhone 3GS升级到iOS 4,5和6,你就可以在同样的硬件上面体验到4倍的性能提升。(在iOS4到iOS5之间性能的巨大的飞跃主要得益于新的Nitro引擎。)实际上SunSpider成绩在iOS7上仍然会有所提高,只是基于保密协议我们这里就不再多说了。跟今天的桌面浏览器相比,最先进的移动浏览器大概还有5倍左右的性能差距 —— 比起09年的30倍已经是相当大的改进。
如果需要了解更多关于iOS硬件和软件性能改进的信息,可以参考Anandtech去年10月份的评测。
在Android平台上也差不多有相当等级的改进。从我们的测试实验室,我们找到了一些可以认为是过去3年里面在当时比较有代表性的高性能机器。我们测试了下面4款手机:
三星Captivate Android 2.2(2010年7月发布)
Droid Bionic Android 2.3.4(2011年9月发布)
三星Galaxy Note 2 Android 4.1.2(2012年9月发布)
三星Galaxy S4 Android 4.2.2(2013年4月发布)
JavaScript的性能持续地快速提升
性能的提升由硬件提升和软件优化同时驱动
虽然高性能的JavaScript是一件好事,但实际上大部分Web应用的性能跟JavaScript性能的关系甚少
幸运的是,其它影响Web应用性能的领域,像DOM操作,Canvas,SVG的性能也在飞速提升
移动平台的速度不及桌面平台的1/5 — 较慢的CPU,还有受限的内存大小和速度和较慢的GPU等等。这些都是无法改变的事实。
移动平台的JavaScript + DOM的访问速度越来越快,但是你始终应该把iPhone 5看作跟2008年在桌面电脑上运行的Chrome 1.0一样 (即比桌面版的IE8快5-10倍)。
移动Web应用的图形性能随着浏览器更多使用GPU进行图形加速和其它通用软件优化,已经基本可以实现30帧每秒的动画。
垃圾收集和平台渲染性能有限的问题仍然会使你困扰,所以使用一个类似Sencha Touch这样的抽象框架来获得更佳性能是十分有必要的。
充分利用移动Web平台提供的远程调试器和性能监控能力:像Chrome for Android现在已经提供了一个不错的fps计数器,还可以显示需要混合的图层边界,这可以告诉你哪些网页内容实际上已经生成了贴图并由GPU负责绘制,还有贴图被加载的次数。
比如文中多处强调JavaScript RAW performance和DOM Interaction的区别,这是因为虽然DOM Interaction虽然也是由JS去调用,但是对浏览器来说,实际上JS只是调用浏览器内核提供的JS Binding API,整个Interaction是由浏览器本身去执行的,所以不应该当作JavaScript本身的性能来考量。
又如浏览器所构建的抽象层的不同部分直接或者间接映射到OS的系统调用或者系统库调用对性能的不同影响的说法要怎么理解?举个例子来说,Web应用开发者可以用DOM+CSS或者用Canvas实现同样的动画效果,下面分别是基于QuarkJS实现的两个同样的动画,一个基于DOM,一个基于Canvas,对于Canvas绘制直接使用OS本身的2D绘图库去实现,并且支持GPU加速的浏览器来说,Canvas动画的效率会比使用DOM要高的多,这是因为基于DOM和CSS的动画,浏览器通常需要进行重新计算样式,重新排版,重新光栅化,重新上传贴图,重新混合等这样一个复杂的流程,效率自然高不起来。再举一个例子,对于支持图层混合加速(Accelerated Compositing)和硬件加速的浏览器来说,对付CSS Transform这样的动画就是小菜一碟,因为对它来说这个动画就是不断改变元素所属图层的Transform属性,然后使用GPU重新混合的过程。而支持硬件加速的浏览器所谓的图层混合其实就是通过OpenGL进行贴图的这样一个过程。
大部分Web应用性能跟JavaScript性能关系不大,对它的要求不高
通过并行化处理是未来浏览器有效提升性能的一个有效手段
首先对于移动设备来说,iOS还好,但是Android由于自身的开放性,硬件水平参差不齐,低端硬件还有相当大的保有量,它们缺乏足够的资源去支持并行化,并行化对它们来说反而更糟糕。不过得益于像MTK这样的芯片厂商大力提升中低端设备的性能,现在的千元机性能已经跟几年前不可同日而言,大概再过多一两年这个问题应该就不再成为问题了。
其次并行化处理并不是想象中的那么容易,因为浏览器的大部分作业实际上都有某种程度的顺序依赖和上下文依赖,需要很多额外的处理才有可能实现部分并行化(毕竟不是数据处理,要做到完全并行化可能性极低)。这样的并行化需要额外的开销,并且只适应于部分场景,有一定的局限性。目前浏览器除了网络链接的部分,并行化程度最高的应该就是渲染了,除了图层混合会运行在独立线程并且主要使用GPU外,像Chrome,Android Browser都把光栅化从主线程剥出来,渲染性能的确从并行化中获益极大,不过也付出了额外的CPU/内存开销的代价。其它领域的并行化进展还是很慢,并且也难见有可能使得性能大幅度提升,比如Chrome在做的HTML解析和样式计算的并行化,最多也就能够减少网页从开始加载到第一次完整呈现的时间,对于整体性能提升意义不大。至于JavaScript,除了IE所实现的JIT并行化外,垃圾收集也是一个有可能剥离出主线程的领域,只是我个人对JavaScript引擎了解不多,不知道具体的技术难点在哪里。
最后还需要前端开发者有意识地去使用并行化,或者为了更好地支持浏览器的并发作业对自己的应用进行专门优化,比如说Web Workers可以让部分JavaScript代码运行在独立的线程,但在实际的网页里面使用的应该很少。
如下图所示,SunSpider的成绩在过去4年的提升非常明显。从Android 2.x到Android4.x就带来了接近3倍的提升。
http://cdn.sencha.io/img/20130730-5-myths-html5/5-html5-myths-2.png
无论是iOS还是Android,这些性能提升都不仅仅是由于摩尔定律本身带来的。过去3年,如果按照摩尔定律,我们期望获得的性能提升大概是4倍左右(18个月提升一倍),但实际上却远远不止,所以软件上的优化的确起了相当大的作用。
更多有意义的测试
如之前我们已经提过的,SunSpider的测试成绩其实越来越不重要,因为它跟应用本身的性能要求关系其实并不大。相反,DOM操作的测试,还有Canvas和SVG的测试成绩对应用的用户体验关系更密切。(理想状态下,我们应该还要去测量改变CSS属性的速度,还有CSS动画,过渡动画和几何变换动画的帧率 —— 因为它们在Web应用中使用的更频繁 —— 不过由于缺少浏览器的支持,仍然无法准确地获取这些测试数据)
第一个DOM操作测试:我们使用了Dromaeo Core DOM测试。下图是之前的4台Android设备上得到的测试成绩,我们把Captivates上的4项Core DOM测试成绩(Attributes,Modifications,Query,Traversal)作为1分,其它设备的测试成绩就是相对于Captivates的得分,然后取4项得分的平均值作为最终结果。
http://cdn.sencha.io/img/20130730-5-myths-html5/5-html5-myths-3.png
如你所见,Android从2.x到4.x带来了3.5倍的性能提升,虽然S4比起Note2的提升幅度比较小。我们在iOS设备上也进行了Dromaeo测试。不幸的是,由于iOS无法降级,我们没法得到老的iOS版本的测试成绩,不过我们仍然可以看到随着硬件的升级,Dromaeo测试性能一样是稳步上升。并且有趣的是,不同的iOS6设备之间的Dromaeo性能提升幅度要大于它们的CPU速度提升幅度,这说明了内存带宽或者缓存的速度提升肯定带来了更大的帮助,所以才能比单纯依靠摩尔定律所能获得的结果更好。
http://cdn.sencha.io/img/20130730-5-myths-html5/5-html5-myths-4.png
为了显示浏览器还有多少潜在的性能提升空间(仅仅是为了赶上其它浏览器表现优异的领域),我们还测试了Surface RT。IE槽糕的DOM操作性能一直困扰着我们,但这说明了Surface RT上的IE10在DOM操作上还有很大的改善空间。这也是我们之前打破的一个神话 —— “移动设备的软件堆栈本身已经足够好,未来没有太多的优化空间”。起码对于Windows RT来说,在DOM操作上还有10倍的差距需要去填补。(我们后面还会展现在哪些测试上,iOS表现不佳)
图形性能
除了展现JavaScript和DOM操作性能的巨大提升外,我们还想为您展现浏览器在Canvas和SVG上的性能提升。我们之前就发现了Canvas2D性能在同样硬件上iOS5比iOS4提升了5-8倍。甚至当iPad 2升级到iOS5后,一些局部测试提升了80倍。并且因为Canvas实际上是对iPhone上的CoreGraphics API的直接调用,所以当原生图形性能获得提升时,Canvas性能也获得了同样的提升。在下面的测试中,我们使用了mindcat Canvas2D benchmark来测试性能。这里,我们看到了随着iPhone硬件的提升(都运行iOS6),Canvas性能也在不断提升。
http://cdn.sencha.io/img/20130730-5-myths-html5/5-html5-myths-5.png
请牢记,上图的显示的数据已经计入了iOS4到iOS5的性能飞跃。如你所见,上图显示出历代iPhone在Canvas2D上的性能提升达到了7倍之多,远比它们的CPU速度提升幅度要大(按照摩尔定律CPU最多也就提升了4倍),这也反映了iPhone的软件堆栈充分利用了CPU/GPU来提升自身的性能。移动Web性能的提升实际上有很大一部分是受益于GPU性能的提升和浏览器更多使用GPU进行图形加速。
http://cdn.sencha.io/img/20130730-5-myths-html5/5-html5-myths-6.png
我们再来看看在Android上运行同样的测试,我们看到一些有趣的数据显示Android上Canvas性能跟CPU性能之间并没有必然的联系。从Android 2.x到Android 4.x上的性能飞跃主要是因为2.x的Canvas完全没有使用GPU加速。这再次说明了,仅仅是浏览器充分利用GPU加速就能够带来巨大的性能提升。
SVG测试
SVG是另外一个可以展现Web性能的广阔的领域。虽然不如Canvas流行(很大程度是因为Canvas已经足够快),SVG的性能随着硬件提升仍然在稳步提升。下图是来自Stephen Bannasch的一个测试,测试了绘制10,000线段构成的一个SVG路径所需的时间。再一次,测试结果显示了各代iPhone CPU/GPU性能提升带来的稳定的SVG性能提升(所有的iPhone都运行iOS6)。
http://cdn.sencha.io/img/20130730-5-myths-html5/5-html5-myths-7.png
但是最大的差距还是源于软件本身:Surface RT比iPhone 5快了30倍(对比iPad4也是如此,虽然这里我们没有列出来)。实际上,Surface RT比起运行在我一年前买的Macbook上的Safari仍然快了10倍!这个差距是是否使用了GPU加速造成的,Window 8/IE10在SVG上充分利用了GPU进行加速,才获得了如此惊人的成果。只要浏览器开发者把更多原来由CPU完成的工作转移到GPU上面去,我们就有可能在iOS和Android上也看到同样的性能提升。
除了上面的长路径绘制外,我们还运行了另外一个来自Cameron Adams的SVG测试,测试了500个不断反弹的小球的动画帧率。再一次,我们可以看到由硬件提升所带来的SVG性能的稳步提升。
http://cdn.sencha.io/img/20130730-5-myths-html5/5-html5-myths-8.png
比起单纯的性能数据,最终的fps值更让人感兴趣。一旦动画超过了30帧,你就可以得到一个跟电影动画(24fps)相似的结果,这样的流畅度已经基本上可以让观看者满意。如果能够达到60帧,那你就会获得由GPU加速带来的极致流畅的体验。
真实世界的性能:垃圾收集,动态语言和更多
我们希望之前的移动性能探索之旅已经说明了一些事情,也打破了一些神话。我们希望为您展现下列真相:
虽然我们可以展现一些高速摄影机下的动画测试,不过实际上所有移动Web应用的开发者都清楚,CSS动画,过渡动画和属性修改的性能从Android 2.1开始已经得到极大的提高,并且它们还在不断提高。
之前我们已经澄清了一些不真实的论断,现在再让我们做一个最终的说明。我们不断听到的各种传言汇总而成的最终结论是“移动Web应用总是很慢,这是因为JavaScript是一种低性能的动态语言,并且垃圾收集机制对性能是一个极大的伤害”。应该说这个结论本身并不是完全错误的。不过如果你的Web应用使用类似Sencha Touch这样的框架来动态产生DOM内容,一个很大的优势在于,我们会在浏览器之上,在特定的应用上下文下,合理地去管理对象的创建和销毁,包括事件对象。这样即使你的应用需要展现无穷尽的数据内容(通过表格,列表或者转盘),我们通过回收DOM对象,过滤多余的事件,对要执行的动作进行优先级排序等优化,可以帮助您的应用获得60fps的视觉动画体验。
如果没有一个中间层进行类似的间接处理,的确很容易得到非常糟糕的移动Web应用体验 —— 就像Facebook移动Web应用的第一个版本一样。我们相信如果应用直接使用类似jQuery Mobile这样直接操作底层DOM模型的UI框架时,在可见的未来的确会持续受到性能相关问题的困扰。
汇总
文中包含了大量的数据和覆盖了不同的主题,最后在这里让我们再总结一下。如果您是一位开发者,您应该可以从这篇文章了解到:
我们希望对这些性能数据的回顾能够帮助我们打破一些虚假的神话。我需要感谢在Sencha的所有人对这篇文章的贡献,包括Ariya Hidayat 的审阅和提供了大量关于浏览器性能优化的文章链接,还有 Jacky Nguyen关于Sencha Touch的抽象层如何进行性能优化的一些实现细节。
翻译后记
喔,终于翻译完了,以前还没有翻译过这么长的文章,没想到还真是一件累死人的事情。每一句话都需要斟字酌句细细体会字面下的意思,再用较为通顺的中文表述出来,无论是脑力还是体力都是相当大的摧残,说多了都是泪啊 =_=
应该说要翻译这篇文章,甚至要读懂这篇文章,译者和读者都需要对浏览器内核的一些工作原理有所了解。
最后要说的是,文中的一些观点还是需要在一定的条件下才能成立的,并不是放之四海而皆准,这是读者需要留意的地方:
是的,大部分是这样的,但不见得你的Web应用就是这大部分之一。实际上,对于有一定复杂程度的基于Canvas的Web Game来说,JavaScript性能很有可能成为它的性能瓶颈。这些Web Game的场景通常比较复杂,包含成百甚至上千的绘图对象(比如实现一个绚丽的粒子效果),需要在JavaScript里面构建一个成百上千个节点的Scene Graph。每绘制一帧,都意味着需要对这个Scene Graph进行遍历,访问每一个节点,更新它的状态,然后再调用Canvas API将它绘制出来。如果要达到30fps的速度,这意味着最多只有30ms左右的时间来完成每一帧(实际上应该没有那么多),即使不算Canvas API本身的绘制开销,单单是遍历和状态更新的操作就很有可能达到几十毫秒的量级了,特别是状态更新中包含大量的碰撞检测和物理运动计算的时候。
应该说,当前通过并行化处理充分利用多核CPU/GPU提升性能是浏览器内核技术研究发展的一个热点。但是并行化并不是银弹,指望它能够短期内戏剧性地大幅度提升浏览器的整体性能并不现实。
最后的话
作为读者,如果您能够一直看到这里,说明您应该对Web App/Game开发是有着真爱的^_^ ,所以不妨再看完这最后一节。从我个人的开发经验来看,一个经过充分优化的应用比起没有经过优化的应用通常会有非常明显的性能差别,如果您的Web App/Game对性能要求很高,并且主要运行在移动平台,那么性能优化对您来说那就更加重要了(移动平台可没有那么多可以挥霍性能的空间)。而为了帮助前端开发者更好地做好性能优化,Chrome提供了可称为逆天的神器Dev Tools,学会使用这套工具(推荐Code School上面的视频教程),然后使用它来对您的应用进行性能分析和优化,您会发现这才是真正能够获得戏剧性的性能飞跃的最大可能,这也是所谓的“求诸人不如求诸己”。
建议继续学习:
- Xvfb+YSlow+ShowSlow搭建前端性能测试框架 (阅读:54289)
- 30分钟3300%性能提升――python+memcached网页优化小记 (阅读:12221)
- Go Reflect 性能 (阅读:10543)
- 长连接(KeepAlive)在 http 连接中的性能影响 (阅读:7153)
- SQL vs NoSQL:数据库并发写入性能比拼 (阅读:6691)
- 服务器性能测试工具推荐 (阅读:6566)
- WEB性能测试工具推荐 (阅读:5727)
- 分析进程内存分配情况,解决程序性能问题 (阅读:5436)
- 移动Web开发初学者指南 (阅读:5171)
- 由12306.cn谈谈网站性能技术 (阅读:5052)
扫一扫订阅我的微信号:IT技术博客大学习
- 作者:易旭昕 来源: UC技术博客
- 标签: 性能 移动Web
- 发布时间:2013-08-21 13:24:10
- [68] IOS安全–浅谈关于IOS加固的几种方法
- [66] Twitter/微博客的学习摘要
- [64] 如何拿下简短的域名
- [61] android 开发入门
- [60] find命令的一点注意事项
- [59] Go Reflect 性能
- [57] 流程管理与用户研究
- [56] Oracle MTS模式下 进程地址与会话信
- [56] 图书馆的世界纪录
- [55] 读书笔记-壹百度:百度十年千倍的29条法则