为什么浏览器采用多进程模型

来源:互联网 发布:电力安装预算软件 编辑:程序博客网 时间:2024/06/16 09:24

为什么浏览器采用多进程模型

这个问题的答案似乎是非常清楚的,可以概括为:为了安全、稳定、性能,只是要牺牲点内存作为代价。对于安全和稳定,利用系统的进程机制就可以完成。但是多进程下的进程间通讯(IPC)很慢,而分为多进程后,一些协作任务就要分开到两个进程,如何能保持良好的性能,更不说比单进程模型更高的性能了? 所以这里再次探讨浏览器选择多进程架构的原因,以及对应架构中的要点。

多进程 vs. 多线程

先了解一下背景。将工作并行处理,是提高性能的手段。这个工作涉及到硬件,操作系统和应用程序。我不性硬件,只知道核是越来越多,线程的处理能力也是越来越强。从系统的角度来看,似乎可以响应并行处理的资源越来越充分。所以研究如何在多核的时代提高应用的性能是当前的一大热点。Intel和IBM都有大量关于并行及并发处理的资料和工具。

无论是多线程,还是多进程,其目的都是充分利用系统的核心资源,如CPU, I/O, GPU及内存等相关的资源,使得任务尽可能的并行完成,以改善应用的响应性能,提高吞吐量。对单个应用而言,其关键是解决并发(Concurrency)的问题 (同时跑多个应用是并行处理的问题)。即找到平衡任务和数据依赖的最佳设计,从系统的角度看主要面临两个挑战: 
1. 系统资源的竞争。如内存,文件系统等。 
2. 上下文切换。 
线程和进程都有上下文切换的开销。但在多核下,进程的上下文开销开始降低。

而从应用程序设计的角度来看,还有两点: 
1. 降低任务依赖。比如执行操作的先后顺序问题。 
2. 降低数据依赖。比如某个数据的修改和使用会影响到多个任务。

上面所列的四个问题中,无论是多进程,还是多线程都要面对。其中多进程在上下文切换的开销上有先天优势。

多进程在安全性和稳定性上优于多线程模型,一是现代系统都有进程的安全机制,特别是沙箱机制。另外单个进程有独立的内存空间,不像多线程共享虚拟内存,所以不会因为一个线程的崩溃导致整个应用的崩溃。

多进程需要面对的问题包括: 
1. 内存占用大,因为无法像多线程模型共享公共的内存开销,比如使用的库,或者某些全局的数据缓存等。这是硬伤。 
2. 进程间通讯的成本大。特别是使用共享内存交换数据的成本。 
3. 进程启动的开销大。

后面两个是性能问题,与前一个并不相同。而且,随着内存配置不断高升,再配合一些内存优化的手段,比如OilPan, 第一个问题并不算太迫切。而后面两个问题,相对于页面渲染的开销,只要限定在一定范围,也不会有太大的影响。所以限定的规则就很重要。

浏览器对多进程的需求

决定浏览器采用多进程架构还是多线程架构,并不是取决于性能。因为从上面的分析也能看出来,多进程模型和多线程模式相比,只要将IPC和启动的开销降低,其性能的高低仍然取决于各个进程中的线程设计。

结合Google和Mozilla对各自采用多进程架构的说明,可以了解到促使浏览器采用多进程架构的是越来越复杂的页面。以下以Chromium的研究论文为主,Mozilla关于Multiprocess Firefox的说明也主要说明之前的性能优化也是可以使用多进程的方式实现的,所以不再详细说明。

现在的页面越来越复杂,H5, Webapp,或者Hybrid App等等,它们执行的任务越来越重,不再像以前都是文档类型的页面,现在的页面更像是一个应用。它们对系统资源的需求变大,同时不稳定的机率也增大。如果同时开启多个页面,就会引入更长的操作延迟,严重影响用户体验。

页面浏览中核心的功能是页面的渲染(从DOM Tree到Render Tree),JS的执行, 它是一个需要集中运算的功能,相对独立于系统资源的使用。而系统资源的使用又可以集中起来共享使用,也有利于将不安全的页面与系统资源隔离开来(沙箱机制的需求)。于是就形成了现在进程架构: 
chrome_architecture 
上面多个Renderer Engines和Plugin-in进程和一个Browser进程构成了Chromium的进程模型。

所以再结合这点思考,为什么Chromium强调对数据库的操作都要抛到Browser进程来完成?

关于性能

我们先看一下Google论证多进程性的数据。他们当时(2009)特别选了一台双核的电脑来进行测试,所有的加载都是从本地文件加载,以避免网络的影响。最终测试的性能数据对比如下: 
process_02_performance 
Startup是启动并且开新页面的时间,New Tab是在新页签打开页面的时间,Navigation则是页面上打开新页面的时间。Monolithic是单进程,另一个不用说了。 
为什么启动并开新页面的时间也变快了?原因当然是进程启动引入的开销其实是很小的,开页面带来的收益要远大于它。

再看一下加载页面到可操作及加载完成所需要的时间: 
process_03_loading 
对于单进程模型,基本要等加载完了才能操作。而多进程模型下,页面渲染与用户操作能够分别响应。当然在单进程模型,利用中断的方式也能达到相似的效果。

这些是Chromium在对IPC和进程中系统资源操作进行严格限制所达到的效果。如果破坏了这些限制,性能就不见得这样理想了。

单进程的Android WebView性能差吗

看一下Google工程师的回复吧:

<span style="font-family:Source Code Pro, monospace;color:rgba(0, 0, 0, 0);"><span style="display: block; box-sizing: border-box; border-radius: 0px; word-wrap: normal; background-image: initial; background-attachment: initial; background-size: initial; background-origin: initial; background-clip: initial; background-position: initial; background-repeat: initial;">By Bo.LiuAny difference </span></span><span class="hljs-keyword" style="box-sizing: border-box;">between</span> multiprocess <span class="hljs-keyword" style="box-sizing: border-box;">and</span> multithread should <span class="hljs-keyword" style="box-sizing: border-box;">not</span> be significant enough <span class="hljs-keyword" style="box-sizing: border-box;">to</span> be noticeable <span class="hljs-keyword" style="box-sizing: border-box;">to</span> users.Webview's rendering <span class="hljs-keyword" style="box-sizing: border-box;">and</span> threading architecture <span class="hljs-keyword" style="box-sizing: border-box;">is</span> different <span class="hljs-keyword" style="box-sizing: border-box;">from</span> chrome, <span class="hljs-keyword" style="box-sizing: border-box;">and</span> what you are probably wanted <span class="hljs-keyword" style="box-sizing: border-box;">to</span> know <span class="hljs-keyword" style="box-sizing: border-box;">is</span> whether this hurts webview's performance.The answer <span class="hljs-keyword" style="box-sizing: border-box;">is</span> depends. Webview merges <span class="hljs-keyword" style="box-sizing: border-box;">some</span> chrome threads <span class="hljs-keyword" style="box-sizing: border-box;">into</span> a single one. The down side <span class="hljs-keyword" style="box-sizing: border-box;">is</span> webview <span class="hljs-keyword" style="box-sizing: border-box;">is</span> more suspetible <span class="hljs-keyword" style="box-sizing: border-box;">to</span> thread contention <span class="hljs-keyword" style="box-sizing: border-box;">and</span> may <span class="hljs-keyword" style="box-sizing: border-box;">not</span> take  advantage <span class="hljs-keyword" style="box-sizing: border-box;">of</span> large <span class="hljs-type" style="box-sizing: border-box;">number</span> <span class="hljs-keyword" style="box-sizing: border-box;">of</span> cpu cores. The up side <span class="hljs-keyword" style="box-sizing: border-box;">is</span>  <span class="hljs-keyword" style="box-sizing: border-box;">that</span> there <span class="hljs-keyword" style="box-sizing: border-box;">is</span> generally less thread hopping, so webview  has an easier <span class="hljs-property" style="box-sizing: border-box;">time</span> performing consistently <span class="hljs-function_start" style="box-sizing: border-box;"><span class="hljs-keyword" style="box-sizing: border-box;">on</span></span> less  powerful hardware.<ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li></ul>

大意为有得有失,关键是“视情况而定”。缺点是线程竞争相对严重了,好处是线程切换少了,性能差的手机也能跑得不错。 引申的意思就是如果是好手机,性能还是有差距的。 还有一个他没说的,单进程下的安全、稳定性又回到过去的状态了,长时间使用后的内存碎片现象也一起回来了。

参考:

Isolating Web Programs in Modern Browser Architectures 
Multiprocess Firefox 
Thread Scheduling in Android)

0 0
原创粉丝点击