blob: 61eaf5065c0519e150aba52637fa596372dd0c2d [file] [log] [blame]
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>WeexCore 多进程多线程架构演进 | WEEX</title>
<meta name="description" content="Weex">
<link rel="icon" href="//gw.alicdn.com/tps/TB1XNqxPXXXXXcSXVXXXXXXXXXX-64-63.png">
<script src="//g.alicdn.com/alilog/mlog/aplus_v2.js"></script>
<meta name="data-spm" dataSpmProtocol="i" content="a2c7j">
<meta name="aplus-ajax" content="chksum">
<meta name="aplus-waiting" content="MAN">
<meta name="google-site-verification" content="FbH8DPHpxdDJlfkKLKXuXWOu69DI8ZRRP8O2Phg8UKw">
<meta name="baidu-site-verification" content="WRr1iWvsYK">
<link rel="preload" href="/assets/css/styles.0ff943f0.css" as="style"><link rel="preload" href="/assets/js/app.0ff943f0.js" as="script"><link rel="preload" href="/assets/js/117.1a9e5539.js" as="script"><link rel="prefetch" href="/assets/css/1.styles.aa72e838.css"><link rel="prefetch" href="/assets/css/10.styles.1fff5b86.css"><link rel="prefetch" href="/assets/css/11.styles.a03faa50.css"><link rel="prefetch" href="/assets/css/2.styles.fc5d9892.css"><link rel="prefetch" href="/assets/css/21.styles.9ebad2b1.css"><link rel="prefetch" href="/assets/css/3.styles.6b94323a.css"><link rel="prefetch" href="/assets/css/36.styles.6dbb9d8c.css"><link rel="prefetch" href="/assets/css/4.styles.706a5607.css"><link rel="prefetch" href="/assets/css/7.styles.469d3b64.css"><link rel="prefetch" href="/assets/css/8.styles.b36167bf.css"><link rel="prefetch" href="/assets/css/9.styles.5bed6ebe.css"><link rel="prefetch" href="/assets/js/10.1fff5b86.js"><link rel="prefetch" href="/assets/js/100.09076a87.js"><link rel="prefetch" href="/assets/js/101.71fa3538.js"><link rel="prefetch" href="/assets/js/102.8a9926d6.js"><link rel="prefetch" href="/assets/js/103.d6c3649e.js"><link rel="prefetch" href="/assets/js/104.adb2425b.js"><link rel="prefetch" href="/assets/js/105.a063ca34.js"><link rel="prefetch" href="/assets/js/106.620e227f.js"><link rel="prefetch" href="/assets/js/107.1c97d156.js"><link rel="prefetch" href="/assets/js/108.d1f236a9.js"><link rel="prefetch" href="/assets/js/109.10a909cc.js"><link rel="prefetch" href="/assets/js/11.a03faa50.js"><link rel="prefetch" href="/assets/js/110.6f9200c8.js"><link rel="prefetch" href="/assets/js/111.9c1831b3.js"><link rel="prefetch" href="/assets/js/112.e5c0d546.js"><link rel="prefetch" href="/assets/js/113.b1c17feb.js"><link rel="prefetch" href="/assets/js/114.c24b95ed.js"><link rel="prefetch" href="/assets/js/115.d7e38c3b.js"><link rel="prefetch" href="/assets/js/116.1aaa95ab.js"><link rel="prefetch" href="/assets/js/118.8d915477.js"><link rel="prefetch" href="/assets/js/119.77f0a126.js"><link rel="prefetch" href="/assets/js/12.16a9b730.js"><link rel="prefetch" href="/assets/js/120.3cf0ba10.js"><link rel="prefetch" href="/assets/js/121.47fefbf1.js"><link rel="prefetch" href="/assets/js/122.3dd022e8.js"><link rel="prefetch" href="/assets/js/123.84abc63f.js"><link rel="prefetch" href="/assets/js/124.2568e233.js"><link rel="prefetch" href="/assets/js/125.5b665f24.js"><link rel="prefetch" href="/assets/js/126.25b58a0a.js"><link rel="prefetch" href="/assets/js/127.d62a58c6.js"><link rel="prefetch" href="/assets/js/128.e5774a02.js"><link rel="prefetch" href="/assets/js/129.9a813c06.js"><link rel="prefetch" href="/assets/js/13.f8bde866.js"><link rel="prefetch" href="/assets/js/130.edddc316.js"><link rel="prefetch" href="/assets/js/131.760aa65c.js"><link rel="prefetch" href="/assets/js/132.559d5ba7.js"><link rel="prefetch" href="/assets/js/133.cbdd35c7.js"><link rel="prefetch" href="/assets/js/134.c02d92e1.js"><link rel="prefetch" href="/assets/js/135.e6d5496a.js"><link rel="prefetch" href="/assets/js/136.8826af60.js"><link rel="prefetch" href="/assets/js/137.28b4573d.js"><link rel="prefetch" href="/assets/js/138.d370fc15.js"><link rel="prefetch" href="/assets/js/139.8d9150fc.js"><link rel="prefetch" href="/assets/js/14.a98602cc.js"><link rel="prefetch" href="/assets/js/140.f0a9b5e1.js"><link rel="prefetch" href="/assets/js/141.297fa6fe.js"><link rel="prefetch" href="/assets/js/142.82bbcbaa.js"><link rel="prefetch" href="/assets/js/143.2d1ed3b2.js"><link rel="prefetch" href="/assets/js/144.69a9bc6a.js"><link rel="prefetch" href="/assets/js/145.74d52c12.js"><link rel="prefetch" href="/assets/js/146.12ecdaf4.js"><link rel="prefetch" href="/assets/js/147.daad4b96.js"><link rel="prefetch" href="/assets/js/148.bb356182.js"><link rel="prefetch" href="/assets/js/149.56fdaace.js"><link rel="prefetch" href="/assets/js/15.ea6e5024.js"><link rel="prefetch" href="/assets/js/150.ee9c4994.js"><link rel="prefetch" href="/assets/js/151.2feae618.js"><link rel="prefetch" href="/assets/js/152.c7703521.js"><link rel="prefetch" href="/assets/js/153.3b555eab.js"><link rel="prefetch" href="/assets/js/154.c6329253.js"><link rel="prefetch" href="/assets/js/155.334c4ea4.js"><link rel="prefetch" href="/assets/js/156.1a29657f.js"><link rel="prefetch" href="/assets/js/157.ba8f07bc.js"><link rel="prefetch" href="/assets/js/158.a60a60ba.js"><link rel="prefetch" href="/assets/js/159.9ce96d49.js"><link rel="prefetch" href="/assets/js/16.14acc638.js"><link rel="prefetch" href="/assets/js/160.2a970224.js"><link rel="prefetch" href="/assets/js/161.a26e2b53.js"><link rel="prefetch" href="/assets/js/162.73535662.js"><link rel="prefetch" href="/assets/js/163.7518a0a5.js"><link rel="prefetch" href="/assets/js/164.17367778.js"><link rel="prefetch" href="/assets/js/165.46c8f055.js"><link rel="prefetch" href="/assets/js/166.1cc22037.js"><link rel="prefetch" href="/assets/js/167.3fbcb5c6.js"><link rel="prefetch" href="/assets/js/168.a3f80f1e.js"><link rel="prefetch" href="/assets/js/169.a6565c29.js"><link rel="prefetch" href="/assets/js/17.d6f2f3b8.js"><link rel="prefetch" href="/assets/js/170.566ddeda.js"><link rel="prefetch" href="/assets/js/171.4fd97bee.js"><link rel="prefetch" href="/assets/js/172.5295c6b9.js"><link rel="prefetch" href="/assets/js/173.ff25fd05.js"><link rel="prefetch" href="/assets/js/174.22ea6a1b.js"><link rel="prefetch" href="/assets/js/175.c6a04367.js"><link rel="prefetch" href="/assets/js/176.d3810924.js"><link rel="prefetch" href="/assets/js/177.facd2802.js"><link rel="prefetch" href="/assets/js/178.f4c6fbe9.js"><link rel="prefetch" href="/assets/js/179.1a3a2c12.js"><link rel="prefetch" href="/assets/js/18.83f6b39a.js"><link rel="prefetch" href="/assets/js/180.b54c8e90.js"><link rel="prefetch" href="/assets/js/181.88495b4c.js"><link rel="prefetch" href="/assets/js/182.8341d23c.js"><link rel="prefetch" href="/assets/js/183.332bcfe2.js"><link rel="prefetch" href="/assets/js/184.d8996a56.js"><link rel="prefetch" href="/assets/js/185.b8584f07.js"><link rel="prefetch" href="/assets/js/186.fa89e23f.js"><link rel="prefetch" href="/assets/js/187.90340eeb.js"><link rel="prefetch" href="/assets/js/188.efe631f8.js"><link rel="prefetch" href="/assets/js/189.72897b1a.js"><link rel="prefetch" href="/assets/js/19.94f071c0.js"><link rel="prefetch" href="/assets/js/190.1ec691ee.js"><link rel="prefetch" href="/assets/js/2.fc5d9892.js"><link rel="prefetch" href="/assets/js/20.13f7bbff.js"><link rel="prefetch" href="/assets/js/21.9ebad2b1.js"><link rel="prefetch" href="/assets/js/22.764b643d.js"><link rel="prefetch" href="/assets/js/23.f533737e.js"><link rel="prefetch" href="/assets/js/24.4eaa533c.js"><link rel="prefetch" href="/assets/js/25.e9877e57.js"><link rel="prefetch" href="/assets/js/26.8905d6a0.js"><link rel="prefetch" href="/assets/js/27.b199a955.js"><link rel="prefetch" href="/assets/js/28.524af0cf.js"><link rel="prefetch" href="/assets/js/29.b772949f.js"><link rel="prefetch" href="/assets/js/3.6b94323a.js"><link rel="prefetch" href="/assets/js/30.f5bcac64.js"><link rel="prefetch" href="/assets/js/31.c55e03aa.js"><link rel="prefetch" href="/assets/js/32.e575600a.js"><link rel="prefetch" href="/assets/js/33.3fff5656.js"><link rel="prefetch" href="/assets/js/34.82598567.js"><link rel="prefetch" href="/assets/js/35.8e1290ba.js"><link rel="prefetch" href="/assets/js/36.6dbb9d8c.js"><link rel="prefetch" href="/assets/js/37.d27fdc88.js"><link rel="prefetch" href="/assets/js/38.f8fc7b20.js"><link rel="prefetch" href="/assets/js/39.bf967d40.js"><link rel="prefetch" href="/assets/js/4.706a5607.js"><link rel="prefetch" href="/assets/js/40.e1864fd6.js"><link rel="prefetch" href="/assets/js/41.61bd3b64.js"><link rel="prefetch" href="/assets/js/42.34d8d61d.js"><link rel="prefetch" href="/assets/js/43.1aee493f.js"><link rel="prefetch" href="/assets/js/44.22177e9b.js"><link rel="prefetch" href="/assets/js/45.5c743d2f.js"><link rel="prefetch" href="/assets/js/46.4feffac9.js"><link rel="prefetch" href="/assets/js/47.367f9103.js"><link rel="prefetch" href="/assets/js/48.0c246d45.js"><link rel="prefetch" href="/assets/js/49.ee354be9.js"><link rel="prefetch" href="/assets/js/5.7d9779f7.js"><link rel="prefetch" href="/assets/js/50.bd81c7f0.js"><link rel="prefetch" href="/assets/js/51.a5f432dd.js"><link rel="prefetch" href="/assets/js/52.537aded4.js"><link rel="prefetch" href="/assets/js/53.84814584.js"><link rel="prefetch" href="/assets/js/54.5f780e97.js"><link rel="prefetch" href="/assets/js/55.9d44c91d.js"><link rel="prefetch" href="/assets/js/56.fc164b43.js"><link rel="prefetch" href="/assets/js/57.959b2d44.js"><link rel="prefetch" href="/assets/js/58.bd5c38e0.js"><link rel="prefetch" href="/assets/js/59.3eaece52.js"><link rel="prefetch" href="/assets/js/6.49a49457.js"><link rel="prefetch" href="/assets/js/60.4b8cb735.js"><link rel="prefetch" href="/assets/js/61.b54b9195.js"><link rel="prefetch" href="/assets/js/62.0116614c.js"><link rel="prefetch" href="/assets/js/63.85b1247d.js"><link rel="prefetch" href="/assets/js/64.8f1be6b5.js"><link rel="prefetch" href="/assets/js/65.6a241647.js"><link rel="prefetch" href="/assets/js/66.08c8bd13.js"><link rel="prefetch" href="/assets/js/67.002e0071.js"><link rel="prefetch" href="/assets/js/68.6c6a7c94.js"><link rel="prefetch" href="/assets/js/69.64d90e5d.js"><link rel="prefetch" href="/assets/js/7.469d3b64.js"><link rel="prefetch" href="/assets/js/70.b2c287c9.js"><link rel="prefetch" href="/assets/js/71.b7ad1135.js"><link rel="prefetch" href="/assets/js/72.7391b5c2.js"><link rel="prefetch" href="/assets/js/73.c5c77d81.js"><link rel="prefetch" href="/assets/js/74.96f80ffd.js"><link rel="prefetch" href="/assets/js/75.2920c7b7.js"><link rel="prefetch" href="/assets/js/76.a90bd3c9.js"><link rel="prefetch" href="/assets/js/77.3a0eeccd.js"><link rel="prefetch" href="/assets/js/78.6791678c.js"><link rel="prefetch" href="/assets/js/79.8b0c78e4.js"><link rel="prefetch" href="/assets/js/8.b36167bf.js"><link rel="prefetch" href="/assets/js/80.2641b89d.js"><link rel="prefetch" href="/assets/js/81.03d1925e.js"><link rel="prefetch" href="/assets/js/82.71061708.js"><link rel="prefetch" href="/assets/js/83.df220a8f.js"><link rel="prefetch" href="/assets/js/84.99fbef8f.js"><link rel="prefetch" href="/assets/js/85.dee8bcae.js"><link rel="prefetch" href="/assets/js/86.5200e4ce.js"><link rel="prefetch" href="/assets/js/87.96df0d82.js"><link rel="prefetch" href="/assets/js/88.e9171a32.js"><link rel="prefetch" href="/assets/js/89.53987bbc.js"><link rel="prefetch" href="/assets/js/9.5bed6ebe.js"><link rel="prefetch" href="/assets/js/90.8da0ff06.js"><link rel="prefetch" href="/assets/js/91.4bcce2cd.js"><link rel="prefetch" href="/assets/js/92.aca18707.js"><link rel="prefetch" href="/assets/js/93.93fdf568.js"><link rel="prefetch" href="/assets/js/94.e893b256.js"><link rel="prefetch" href="/assets/js/95.cb1d62b6.js"><link rel="prefetch" href="/assets/js/96.5529545c.js"><link rel="prefetch" href="/assets/js/97.d01eda68.js"><link rel="prefetch" href="/assets/js/98.384bebd6.js"><link rel="prefetch" href="/assets/js/99.fa349b8f.js"><link rel="prefetch" href="/assets/js/vendors~docsearch.aa72e838.js">
<link rel="stylesheet" href="/assets/css/styles.0ff943f0.css">
</head>
<body>
<div id="app" data-server-rendered="true"><div class="theme-container vuepress-theme-fast"><header class="navbar"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div><a href="/zh/" class="home-link router-link-active"><img src="/logo@2x.svg" alt="WEEX" class="logo"></a><span class="version"><a href="/download/download.html" class="version-bg"><img src="/assets/img/version-bg.ab65ded9.svg" alt="v0.28"><span class="version-no">v0.28</span></a></span><div class="links"><form id="search-form" class="algolia-search-wrapper search-box"><input id="algolia-search-input" class="search-query"></form><nav class="nav-links can-hide"><div class="nav-item"><a href="/zh/guide/" class="nav-link">指南</a></div><div class="nav-item"><a href="/zh/docs/" class="nav-link">文档</a></div><div class="nav-item"><a href="/zh/tools/" class="nav-link">第三方工具</a></div><div class="nav-item"><a href="/zh/download/" class="nav-link">下载</a></div><div class="nav-item"><a href="/zh/community/" class="nav-link">社区</a></div><div class="nav-item"><a href="/zh/blog/" class="nav-link router-link-active">博客</a></div><div class="nav-item"><div class="dropdown-wrapper"><a class="dropdown-title"><span class="title">选择语言</span><span class="arrow right"></span></a><ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----><a href="/" class="nav-link">English</a></li><li class="dropdown-item"><!----><a href="/zh/blog/weexcore-multiprocess-evolution.html" class="nav-link router-link-exact-active router-link-active">简体中文</a></li></ul></div></div></nav><a href="https://github.com/apache/incubator-weex" target="_blank" rel="noopener noreferrer" class="repo-link"><img src="/assets/img/github.7cb484a9.svg" alt="github" class="github-icon"></a></div></header><div class="sidebar-mask"></div><div class="sidebar"><nav class="nav-links"><div class="nav-item"><a href="/zh/guide/" class="nav-link">指南</a></div><div class="nav-item"><a href="/zh/docs/" class="nav-link">文档</a></div><div class="nav-item"><a href="/zh/tools/" class="nav-link">第三方工具</a></div><div class="nav-item"><a href="/zh/download/" class="nav-link">下载</a></div><div class="nav-item"><a href="/zh/community/" class="nav-link">社区</a></div><div class="nav-item"><a href="/zh/blog/" class="nav-link router-link-active">博客</a></div><div class="nav-item"><div class="dropdown-wrapper"><a class="dropdown-title"><span class="title">选择语言</span><span class="arrow right"></span></a><ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----><a href="/" class="nav-link">English</a></li><li class="dropdown-item"><!----><a href="/zh/blog/weexcore-multiprocess-evolution.html" class="nav-link router-link-exact-active router-link-active">简体中文</a></li></ul></div></div></nav><ul class="sidebar-links"><li><a href="/zh/blog/write-a-blog.html" class="sidebar-link">写一篇博客</a></li><li><a href="/zh/blog/weex-auto-test-locating.html" class="sidebar-link">Weex自动化测试元素定位方案</a></li><li><a href="/zh/blog/ios-weexcore.html" class="sidebar-link">iOS WeexSDK 接入 WeexCore</a></li><li><a href="/zh/blog/weexcore-multiprocess-evolution.html" class="active sidebar-link">WeexCore 多进程多线程架构演进</a><ul class="sidebar-sub-headers"></ul></li><li><a href="/zh/blog/interaction-optimization.html" class="sidebar-link">可交互时间的探索和首屏时间的改进之路</a></li><li><a href="/zh/blog/what_is_the_most_important_assest_to_an_open_souce_project.html" class="sidebar-link">什么是一个开源项目最重要的资产?</a></li><li><a href="/zh/blog/weex-third-party-extensions.html" class="sidebar-link">Weex 三方插件</a></li></ul></div><div class="page"><div class="content"><h1 id="weexcore-多进程多线程架构演进"><a href="#weexcore-多进程多线程架构演进" class="header-anchor">#</a> WeexCore 多进程多线程架构演进</h1><h3 id="_1-背景"><a href="#_1-背景" class="header-anchor">#</a> 1. 背景</h3><p><code>Weex Android</code> 早在 2016 年时就采用了多线程的模型来提升 <code>Weex</code> 的渲染能力. <code>DomThread</code>, <code>JSThread</code>, <code>UIThread</code> . 去年双十一 <code>Weex</code> 进化成多进程模式来提升 <code>Weex</code> 的稳定性. 所以理论上来说, Weex 早就是多进程多线程的模式了, 为什么现在还在谈这个事情. 且听我慢慢重新介绍一些目前的 <code>WeexCore</code></p><p><code>WeexCore</code> 在今年三月份的时候, 加入了一个新的成员, 叫 <code>LayoutEngine</code>, 它的算法都沉到 c++ 层. 而且一同带下来的还有它的合作伙伴 <code>Parser</code>. 这样, <code>DOM 解析</code><code>Layout</code> 全家桶就全部进入了 <code>JSThread</code>. 在减少一个线程的情况下, Weex 的渲染性能还能有所提升, 足以说明目前的 <code>LayoutEngine</code> 的强大.</p><p>演变过程大致如下图所示, 黄色 DOMParser 本来在一个独立的线程里, 现在和绿色块合成了一个线程.
<img src="/blog/weexcore-multiprocess-evolution/f31103153fd160ae4723069f88c61e34.png" alt="2018-12-07 at 13.18.png"></p><p>再说说多进程, Weex 的 jsEngine 从 V8 切到了 JavaScriptCore. 但由于以下几个问题, 所以将 JSC 引擎放到了子进程里运行.</p><ol><li>在JSC引擎上线出现许多无定位的稳定性问题,威胁手淘等使用Weex的客户端的稳定性。</li><li>JSC容易耗TLS(Thread Local Storage),导致TLS slot耗尽,易引起其他模块的崩溃。</li><li>JSC引擎性能虽好,但是占用内存较大,在低端机容易引起内存吃紧,导致手淘进程被杀。</li></ol><p>这套多进程架构在当时来看是非常完美的, 采用多进程模型切到 jscEngine, 既提升了渲染能力, 也提升了 Weex 的整体稳定性.</p><p>但这种模型在某些方面还是存在不足, 例如虽然是多进程, 但实际上还是单线程的运作模式, 且子进程无法主动向主进程发送消息. 而且 Native 定时器也无法友好的实现.</p><p>先说说为什么多进程下, 为什么还是单线程的模型.</p><p><img src="/blog/weexcore-multiprocess-evolution/872298694d6e7f1a311ade626da0f0f8.png" alt="2018-12-07 at 11.29.png"></p><p>如上图所示, 一块共享内存分为16份, 父进程(WeexCore) 写偶数块, 读奇数块. 子进程(JSS) 写奇数块, 读偶数块.</p><p>初始化时, 父进程锁住 0 内存块. 子进程锁住 1 内存块, 子进程启动监听, 请求锁 0 内存块. 但此时 0 内存块被父进程锁着, 所以子进程请求锁 0 内存块失败, wait 父进程释放 0 内存块. 就这样, 两个进程因为互相竞争一块共享内存, 所以变相的成为单线程模式. 既同一时间只有一个进程能够保持活跃状态.</p><p>这意味着当前模型下, <strong>Weex 所有的操作入口只能是 Platform 层, 子进程只能响应父进程的任务, 不能主动的执行某个任务, 且父进程在执行 Layout 或 parser 操作时, JSEngine 是处于挂起的状态的.</strong></p><p>所以, WeexCore 的线程模型演变成下面这个样子.</p><p><img src="/blog/weexcore-multiprocess-evolution/cc6710bafd8edd87a577c72d89a764fb.png" alt="2018-12-07 at 12.23.png"></p><p>从架构上来说, 主要有以下几个变动</p><ul><li><ol><li>WeexCore 演变成消息驱动的线程异步交互模型.</li></ol></li></ul><ul><li>新增 I/O Thread 来拓展原有单向的 IPC, 使子进程可主动的向父进程发送消息. I/O Thread 只用来任务转发, 相比之前还需 wait 任务执行完毕, 效率提升非常明显.</li><li>新增 JS Thread 来专门的执行 js 任务. 不再受上层 Layout 和 Parser 任务的阻塞.</li><li>针对 NativeTimer 新增一个 Timer 线程来做定时器计算, 这个后面会具体讲到.</li></ul><ul><li><ol start="2"><li>WeexCore 分层设计. IPC 可热插拔的自由切换</li></ol></li></ul><h3 id="_2-详解"><a href="#_2-详解" class="header-anchor">#</a> 2. 详解</h3><h4 id="_2-1-消息驱动的异步通信模型"><a href="#_2-1-消息驱动的异步通信模型" class="header-anchor">#</a> 2.1. 消息驱动的异步通信模型</h4><p>线程的异步通信模型可以避免线程间互不阻塞,提⾼高线程的并发性
<img src="/blog/weexcore-multiprocess-evolution/937def357b6528b0d78f0e948560e5dc.png" alt="2018-12-07 at 12.36.png"></p><p>异步通信可以通过简单的控制线程共享的 volatile 变量或者信号量 mutex 和条件异步调⽤用到其他线程 的函数块,然⽽简单粗暴的使⽤用这些⽅式时,线程的边界会变得不明显或者代码块都充斥着锁和信号量的控制,如果数据需要线程公用,还需要对数据块上锁,导致死锁或异步能⼒下降,对本身代码的维护和程序的稳定性都有影响。
消息驱动的异步通信模型结是常用的线程循环模型,是一种非侵⼊式设计,消息结构耦合度底,线程中的循环实现灵活度高。尽管它也是基于上述的⽅式去进⾏线程切换,但相⽐起直接对⽅法⽤锁,或者直接利用 volatile,通过消息使代码块和数据边界明显,提⾼了程序的线程安全性,线程间互不阻塞,提⾼线程的并发性。它代表着⼀种设计哲学,但是这并不是代表它没有任何锁控制,只是可以把锁限制在⼀个极⼩的范围内。
技术要点</p><ol><li>跨平台、⾼高效、易易⽤用的消息驱动的异步通信模型。</li><li>能适应当前 Weex 的线程模型——不不改变上层 Platform 层的线程模型,WeexCore 能兼容上层
的消息循环机制,例例如 Android Handler。</li></ol><h5 id="_2-1-1-总体设计"><a href="#_2-1-1-总体设计" class="header-anchor">#</a> 2.1.1 总体设计</h5><p><img src="/blog/weexcore-multiprocess-evolution/4545bcabcdac57acfe0be1692a8b9cc5.png" alt="2018-12-07 at 12.40.png"></p><p>上图是消息驱动框架的简要类关系图,整体的流程是创建或者依附到 Thread 环境,通过消息泵 MessagePump 完成线程切换,驱动消息循环体 MessageLoop 进⾏消息循环,在当前线程中执⾏来自于其他线程丢进池⼦中的消息。</p><ul><li>Thread ⽤用于构建当前线程环境,当模式是依附到 Android 或 iOS 的线程时,Thread 是⼀一个⽤用 来装载 MessageLoop 的壳⼦,不会新构建任何线程环境。</li><li>MessageLoop 是真正进⾏消息执⾏和存储的对象。它实现了 MessagePump::Delegate 的接⼝,表示它能接受来⾃消息泵的驱动</li><li>MessagePump 是⼀个消息泵,即驱动器,负责及时或定时切换线程环境,驱动消息循环,完成 消息从⼀个线程传递到另⼀个线程的执⾏的过程</li></ul><h5 id="_2-1-2-具体流程"><a href="#_2-1-2-具体流程" class="header-anchor">#</a> 2.1.2 具体流程</h5><p>下⾯将从 Thread 创建过程中相关对象的创建流程图、消息循环初始化流程图和消息驱动流程图上分 析,通过具体流程可以了解内部对跨平台和对当前 Weex 的上层线程模型的适配机制。</p><p><img src="/blog/weexcore-multiprocess-evolution/7d0c65a3a4b79ac3d990dfaa8f203be1.png" alt="2018-12-07 at 12.42.png"></p><p>上图是 Thread 创建过程中相关对象的创建流程图。当外界通过 new 创建 Thread 时,需要带上 MessageLoop::Type 的参数(关键:⽤于创建 MessagePump,启动时会根据类型判断是否要创建线 程环境)。ThreadImpl 是 Thread 的实现类,是真正⽤于创建 Thread 环境的对象,它是⼀个抽象类,它的⼦类后缀分别是 Android / iOS / Posix。这些⼦类分别代表了各个环境下的实现。Android 和 iOS 都是 Unix-like 系统,因此他们使⽤的都是 Posix 线程,但是在 pthread 的操作上会有不⼀致 的地⽅,例如 pthread_setname_np 在 Android 和 iOS 上传递的参数不⼀样。因此根据不同系统去 对应的对实现类做出调整。Thread 在初始化 Impl 时会根据宏定义确定初始化的 Impl ⼦类,从⽽做到平台适应。</p><p>ThreadImpl 持有⼀个维护消息队列的 MessageLoop,再初始化时也会⼀并创建。MessageLoop 中 持有⼀个驱动器 MessagePump,MessagePump 是⼀个接⼝类,具体实现类由 MessageLoop::Type 决定。MessageLoop::Type 具有两种类型,DEFAULT 指驱动器由默认的 Posix Thread ⽅式进⾏,PLATFORM 指驱动器由兼容 Android 或 iOS 的线程环境和消息循环⽅式实现(具体循环请继续向后)。</p><p><img src="/blog/weexcore-multiprocess-evolution/950b476fb53468ba2f309b73435a9e15.png" alt="2018-12-07 at 12.43.png"></p><p>上图是消息循环初始化流程图。当 Thread 创建完成后,需要通过 Thread::Start ⽅法完成内部消息循 环的构建流程。Thread::Start ⽅法会通过实现类 ThreadImpl::Run 完成,ThreadImplPosix 是 Android / iOS 的基类,基类中 Run ⽅法会对 MessageLoop::Type 进⾏判断:</p><ul><li>如果是 PLATFORM ⽆需创建新的线程环境,⽽是直接依附到当前线程,紧接着调⽤ MessageLoop::Run</li><li>如果是 DEFAULT 类型,则需要通过 pthread_create 初始化线程环境,并在新线程中执⾏ MessageLoop::Run。这⾥有⼀个⼩点,为了确保外部执⾏完 Start 后可以执⾏抛消息操作 ,当 前线程会通过 WaitableEvent 同步等待新线程完成初始化。</li></ul><p>MessageLoop 在这⾥的作⽤只是⽤于执⾏消息和存储消息,因此 MessageLoop::Run 并不会进⼊⽆ 限循环,它将这个动作交由驱动器 MessagePump 决定是进⼊⽆限循环还是依附上层。</p><ul><li>在 MessagePumpPosix 情况下,必然是⼀个不依附与上层的新线程,整体的循环由⾃⼰把控, Run ⽅法内部通过信号量 mutex 和条件 condition 进⼊等待消息状态。</li><li>在 MessagePumpAndroid 情况下,Run ⽅法内部主要通过 jni ⽅法创建和绑定 java 层 SystemMessageHandler 对象,建⽴和上层 Android 消息循环机制的关联。</li><li>在 MessagePumpDarwin 情况下,Run ⽅法内部通过获取当前线程的 CFRunLoopRef 和创建 CFRunLoopSourceRef 对象,建⽴和上层 iOS 消息循环机制的关联。</li></ul><p>到此消息循环的初始化流程完成,DEFAULT 类型进⼊了线程阻塞等待唤醒,⽽ PLATFORM 类型进⼊ 了等待来⾃ Android / iOS 的调度。</p><p><img src="/blog/weexcore-multiprocess-evolution/965358b8880bc1e1547654ca3f26b79a.png" alt="2018-12-07 at 12.45.png"></p><p>上图是消息驱动流程图。当外界在其他线程通过指定线程的 MessageLoop 进⾏ PostTask 传进来了⼀ 个任务 closure,内部会对 DelayedTaskQueue 上锁,确保安全的添加操作,此时 closure 会变成 DelayedTask 扔进池⼦⾥,释放锁。通知消息泵有消息进来:</p><ul><li>如果是 MessagePumpPosix,将会通过 condiion::notify_one 唤醒对应线程,对应线程将进⼊ MessageLoop::DoWork</li><li>如果是 MessagePumpAndroid,将会通过 jni 到上层 SystemMessageHandler 的 scheduleWork ,向 Android handler 抛消息,切换到对应线程,再回调到底层的 MessageLoop::DoWork</li><li>如果是 MessagePumpDarwin,将对 CFRunLoopSourceRef 对象标记待处理,再通过 CFRunLoopWakeUp 唤醒线程,切换到对应线程,再回调到底层的 MessageLoop::DoWork</li></ul><p>MessageLoop::DoWork 中⾸先对 DelayedTaskQueue 上锁,通过对⽐ DelayedTask 时间和当前时 间获取需要执⾏的 closure 列表,如果还有任务,则通知消息泵定时驱动,接着释放锁,执⾏ closure 列表。结束后如果是 MessagePumpPosix,则需阻塞当前线程,等待下次唤醒。</p><h5 id="_2-1-3-closure-设计"><a href="#_2-1-3-closure-设计" class="header-anchor">#</a> 2.1.3 closure 设计</h5><p><img src="/blog/weexcore-multiprocess-evolution/1b94848aaa731b146228090093b5cc92.png" alt="2018-12-07 at 12.47.png"></p><p>closure 是⼀个任务的载体,它实际是⼀个 std::function。它在被扔进任务池⼦⾥⾯时,它的⽣命周 期就跟随着线程,除⾮它离开了执⾏队列被执⾏,那么它的⽣命周期将在执⾏后被销毁,否则未被执 ⾏的任务将在执⾏完后⾃动析构。⽽这个可以拷⻉的 function 是通过 CopyableLambda 实现的, CopyableLambda 通过创建⼀个指向数据的共享指针,然后创建⼀个可复制的 lambda 来捕获该共享 指针,然后将该可复制的 lambda 包装成 std::function 请求的签名,赋予 std::function 函数拷⻉的 功能,可供 MessageLoop 持有调度。</p><p>由于涉及了跨线程传递参数对象,因此参数对象尤其是指针的⽣命周期管理需要异常⼩⼼。 std::function ⽀持使⽤ lambda 表达式,在 lambda 表达式中要善⽤智能指针,确保指针的⽣命周期 在 task 结束仍然有效,例如使⽤ unique_ptr 将指针的⽣命周期转移交给 task。</p><h5 id="_2-1-4-使⽤姿势"><a href="#_2-1-4-使⽤姿势" class="header-anchor">#</a> 2.1.4 使⽤姿势</h5><p>以 WeexCore 的例⼦为例,当 JSS 从 IO 线程向 WeexCore 发送了 CallNative 的指令,那么在 WeexCore 中回到 JS 线程的⽅式是:</p><div class="language-c++ extra-class"><pre class="language-text"><code>WeexCoreManager::Instance()-&gt;script_thread()-&gt;message_loop()-&gt;PostTask(
weex::base::MakeCopyable([page_id = std::string(page_id), task = std::string(task), callback = std::string(callback)] {
// CallNative
}));
</code></pre></div><h4 id="_2-2-weexcore-分层设计"><a href="#_2-2-weexcore-分层设计" class="header-anchor">#</a> 2.2. WeexCore 分层设计</h4><p>IPC 可热插拔, 单双进程自由切换</p><p><img src="/blog/weexcore-multiprocess-evolution/22195f7e61b2267f50dc78226d98aff3.png" alt="2018-12-07 at 13.05.png"></p><p>如图所示.</p><p>Weex 目前整体可以分为三层</p><ol><li>Platform(Android, iOS, ..)</li><li>WeexCore(Layout, Parser)</li><li>JSS(JSEngine 子进程).</li></ol><p>我们在每个层面之间加入了一个 Bridge, 每个 Bridge 对应两个 Side. 每个 Side 对应三种模式</p><ol><li>Multi Process: 多进程模式, 通过IPC 通信.</li><li>Multi So: 多 So 模式, 通过函数指针互相调用.</li><li>Simple: 内部模式, 可以互相调用.</li></ol><p>例如目前 Weex 的多进程模式是 PlatformBridge 对应的Side 为 Simple, ScriptBridge 的 side 都是 MultiProcess.</p><p>如果 IPC 上移, 或者切换单进程不使用 IPC, 只需要切对应的 Side 即可.</p><h3 id="_3-效果"><a href="#_3-效果" class="header-anchor">#</a> 3. 效果</h3><p>多线程架构完成之时, 测试同学进行了一次完整的性能测试, 在复杂的页面下,性能提升比较明显, 多线程架构上线之后, 通过线上埋点观察到性能也有了不小的提升.</p><p>多线程架构给 Weex 带来的不仅仅是性能上的提升, 个人认为高拓展性才是最大的收益.
例如 NativeTimer 和未来即将做的 Native DomAPI 在老的架构下是无法做出来的.</p><p>目前 Weex 的很多逻辑都沉入了 c 层, JSFramework 的能力也上浮到客户端来做,
不久的将来 WeexCore 将做到平台无关, JSFramework 全 Native 化, 欢迎有兴趣的同学一起来共建 WeexCore.</p></div><div class="page-nav"><p class="inner"><span class="prev">
<a href="/zh/blog/ios-weexcore.html" class="prev">
iOS WeexSDK 接入 WeexCore
</a></span><span class="next"><a href="/zh/blog/interaction-optimization.html">
可交互时间的探索和首屏时间的改进之路
</a>
</span></p></div><div class="page-edit"><div class="last-updated"><span class="prefix">上次更新: </span><span class="time">2020/12/10</span></div><div class="edit-link"><a href="https://github.com/apache/incubator-weex-site/edit/master/docs/zh/blog/weexcore-multiprocess-evolution.md" target="_blank" rel="noopener noreferrer">编辑此页</a><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><a href="https://github.com/apache/incubator-weex-site/issues/new?body=https%3A%2F%2Fweex.io%2F" target="_blank" rel="noopener noreferrer" class="issueText">提交建议</a><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></div><div class="score"><span class="choice"><img src="https://img.alicdn.com/tfs/TB1h7TSqpYqK1RjSZLeXXbXppXa-20-18.svg" class="score-icon">文档写得很棒</span><span class="choice"><img src="https://img.alicdn.com/tfs/TB1h7TSqpYqK1RjSZLeXXbXppXa-20-18.svg" class="score-icon bad">文档写得很差</span></div></div><div class="license-wrap" style="display:none;"><footer class="footer-container" data-v-0ad13d84><div class="footer-body" data-v-0ad13d84><img src="/logo@2x.svg" class="logo" data-v-0ad13d84><img src="//img.alicdn.com/tfs/TB11BRiIW6qK1RjSZFmXXX0PFXa-365-365.png" class="apache" data-v-0ad13d84><div class="cols-container" data-v-0ad13d84><div class="col col-12" data-v-0ad13d84><h3 data-v-0ad13d84>Disclaimer</h3><p data-v-0ad13d84>Apache Weex is an effort undergoing incubation at The Apache Software Foundation (ASF), sponsored by the
Incubator. Incubation is required of all newly accepted projects until a further review indicates that the
infrastructure, communications, and decision making process have stabilized in a manner consistent with
other successful ASF projects. While incubation status is not necessarily a reflection of the completeness
or stability of the code, it does indicate that the project has yet to be fully endorsed by the ASF.</p></div><div class="col col-4" data-v-0ad13d84><dl data-v-0ad13d84><dt data-v-0ad13d84>ASF</dt><dd data-v-0ad13d84><a href="http://www.apache.org" target="_self" data-v-0ad13d84>Foundation</a></dd><dd data-v-0ad13d84><a href="http://www.apache.org/licenses/" target="_self" data-v-0ad13d84>License</a></dd><dd data-v-0ad13d84><a href="http://www.apache.org/events/current-event" target="_self" data-v-0ad13d84>Events</a></dd><dd data-v-0ad13d84><a href="http://www.apache.org/foundation/sponsorship.html" target="_self" data-v-0ad13d84>Sponsorship</a></dd><dd data-v-0ad13d84><a href="http://www.apache.org/foundation/thanks.html" target="_self" data-v-0ad13d84>Thanks</a></dd></dl></div><div class="col col-4" data-v-0ad13d84><dl data-v-0ad13d84><dt data-v-0ad13d84>Documentation</dt><dd data-v-0ad13d84><a href="/guide/develop/create-a-new-app.html" target="_self" data-v-0ad13d84>Quick start</a></dd><dd data-v-0ad13d84><a href="/guide/develop/setup-develop-environment.html" target="_self" data-v-0ad13d84>Developer guide</a></dd></dl></div><div class="col col-4" data-v-0ad13d84><dl data-v-0ad13d84><dt data-v-0ad13d84>Resources</dt><dd data-v-0ad13d84><a href="/blog/write-a-blog.html" target="_self" data-v-0ad13d84>Blog</a></dd><dd data-v-0ad13d84><a href="/community/" target="_self" data-v-0ad13d84>Community</a></dd><dd data-v-0ad13d84><a href="/guide/contribute/thanks.html" target="_self" data-v-0ad13d84>Thanks by Weex</a></dd><dd data-v-0ad13d84><a href="https://www.apache.org/security/" target="_self" data-v-0ad13d84>Security</a></dd></dl></div></div><div class="copyright" data-v-0ad13d84><span data-v-0ad13d84>Copyright © 2018-2019 The Apache Software Foundation. Apache and the Apache feather
logo are trademarks of The Apache Software Foundation.</span></div></div></footer></div></div><!----></div></div>
<script src="/assets/js/app.0ff943f0.js" defer></script><script src="/assets/js/117.1a9e5539.js" defer></script>
</body>
</html>