What the heck is the event loop?
前几天看了一个youtube视频,关于JavaScript运行原理的,讲的比较透彻,在此记录一下。 这位老兄为此还写了一个可以实时看到js运行时动画的程序,实属牛逼。 这位老兄的博客地址:http://latentflip.com
前几天看了一个youtube视频,关于JavaScript运行原理的,讲的比较透彻,在此记录一下。 这位老兄为此还写了一个可以实时看到js运行时动画的程序,实属牛逼。 这位老兄的博客地址:http://latentflip.com
这篇译章探究了NodeJS的架构和单线程事件循环模型。我们将在本文中讨论“NodeJS如何在底层工作,它遵循什么类型的处理模型,NodeJS如何使用单线程模型处理并发请求”等内容。 NodeJS 单线程事件循环模型 正如我们刚才说的,NodeJS使用的是“单线程事件循环模型”的架构去处理多个并发的客户端请求的。 有许多Web应用程序技术,如JSP,Spring MVC,ASP.NET等。但所有这些技术都遵循“多线程请求 - 响应”架构来处理多个并发客户端。 我们已经熟悉“多线程请求 - 响应”架构,因为它被大多数Web应用程序框架使用。 但是为什么NodeJS选择了不同的架构来开发Web应用程序。多线程和单线程事件循环体系结构之间的主要区别是什么? NodeJS NodeJS使用“单线程事件循环模型”架构来处理多个并发客户端。然而它是如何真正处理并发客户端请求且不使用多个线程。什么是事件循环模型?我们将逐一讨论这些概念。 在讨论“单线程事件循环”架构之前,首先我们将介绍著名的“多线程请求 - 响应”架构。 传统的Web应用处理模型 任何非NodeJS开发的Web应用程序通常都遵循“多线程请求 - 响应”模型。我们可以将此模型称为请求/响应模型。 客户端向服务器发送请求,然后服务器根据客户端请求进行一些处理,准备响应并将其发送回客户端。 该模型使用HTTP协议。由于HTTP是无状态协议,因此该请求/响应模型也是无状态模型。所以我们可以将其称为请求/响应无状态模型。 但是,此模型使用多线程来处理并发客户端请求。 在讨论这个模型内部之前,首先要看下面的内容。 请求/响应模型处理的步骤: 客户端发送一个请求到Web服务器 Web服务器内部维护一个有限的线程池,以便在客户端请求提供服务 Web服务器处于无限循环中并等待客户端传入请求 Web服务器处理请求步骤: 接收到一个客户端请求 从线程池中选择一个线程 将此线程分配给客户端请求 此线程读取客户端请求,处理客户端请求,执行阻塞的IO操作(如果需要)和准备响应 此线程将准备好的请求发送回Web服务器 Web服务器又将此响应发送到相应的服务器 服务器为所有客户端执行以上步骤,为每一个客户端请求创建一个线程。 图表说明: Client-1, Client-2, …, Client-n是同时发送请求到Web服务器的客户端应用 Web服务器内部维护着一个有限的线程池,线程池中线程数量为m个 Web服务器逐个接收这些请求: Web服务器拾取Client-1的请求Request-1,从线程池中拾取一个线程T-1并将此请求分配给线程T-1 线程T-1读取Client-1的请求Request-1, 并处理该请求 该请求无阻塞IO处理 处理完必要的步骤后准备将Response-1发送回客户端 Web服务器又将此Response-1发送到Client-1 Web服务器拾取Client-2的请求Request-2,从线程池中拾取一个线程T-2并将此请求分配给线程T-2 线程T-2读取Client-2的请求Request-2, 并处理该请求 该请求无阻塞IO处理 处理完必要的步骤后准备将Response-2发送回客户端 Web服务器又将此Response-2发送到Client-2 Web服务器拾取Client-n的请求Request-n,从线程池中拾取一个线程T-n并将此请求分配给线程T-n 线程T-n读取Client-n的请求Request-n, 并处理该请求 Request-n需要大量的阻塞IO和计算操作 线程T-n需要更多时间与外部系统(SQL, File System)交互,执行必要步骤并准备Response-n并将其发送回服务器 Web服务器又将此Response-n发送到Client-n 如果’n’大于’m’(大多数时候,它是真的),则在使用完所有的m个线程之后,剩余的客户端请求会在队列中等待。 如果这些线程中有大量的阻塞IO操作(例如:和数据库、文件系统、外部服务等交互),那么剩余的客户端也会等待更长的时间。 一旦线程池中的线程空闲且可用于下一个任务,服务器就会拾取这些线程并将它们分配给剩余的客户端请求。 每个线程都会使用到许多资源,如内存等。因此,在将这些线程从忙状态转到等待状态之前,它们应该释放所有获取的资源。 请求/响应无状态模型的缺点: 在处理越来越多的并发客户端请求时会变得棘手 当客户端请求增加时,线程也会越来越多,最后它们会占用更多内存。 客户端可能需要等待服务器释放可用的线程去处理其请求 处理阻塞式的IO任务时浪费时间 NodeJS的架构 - 单线程事件循环 NodeJS不遵循请求/响应多线程无状态模型。 它采用单线程与事件循环模型。 NodeJS的处理模型主要基于Javascript基于事件的模型和Javascript回调机制。...
http://arewefastyet.com 网站测试并展示了数个 JavaScript 引擎的性能数据,是各家 JS 引擎性能的比武场: 我们看到在这个比武场上,最近 Chrome 出现了多个新条目,其中很多条目都是关于 v8 的 Ignition 新架构的组合,他们是 v8 引擎最近推出的 JS 字节码解释器。 纵览各个 JS 引擎的实现,我们发现基于字节码的实现是主流。例如苹果公司的 JavaScriptCore (JSC) 引擎,2008 年时他们引入了 SquirrelFish(市场名 Nitro),实现了一个字节码寄存器机(Register Machine)。再如 Mozilla 公司的 SpiderMonkey,他们使用字节码的历史更久,可以追溯到 1998 年的 Netscape 4(见 https://dxr.mozilla.org/classic/source/js/src/jsemit.c ),SpiderMonkey 实现的是堆栈机(Stack Machine)。微软的 Chakra 也使用了字节码,他们实现的是寄存器机(Register Machine)。而 v8 之前的做法是比较“脱俗”的,他们跳过了字节码这一层,直接把 JS 编译成机器码。而在刚刚过去的五一假日前夕,v8 5.9 发布了,其中的 Ignition 字节码解释器将默认启动 :https://v8project.blogspot.co.id/2017/04/v8-release-59.html 。v8 自此回到了字节码的怀抱。 这让笔者不禁怀念起 2007 年 Ruby 1.9 的发布。当时 Ruby 1.9 也是第一次引入了字节码,名为 YARV,由笹田耕一领导主导开发完成。当时,Ruby 还在使用松本行弘的初级的解释器实现,亦即,解释器每次遍历代码的抽象语法树(AST)来进行 Ruby 代码的解释执行。而 YARV 则把抽象语法树(AST)先编译成字节码,然后再运行。引入字节码之后,Ruby 的性能得到了显著的提升。 而这次 V8 引入字节码却是向着相反的方向后退。因为之前 v8 选择了直接将 JS 代码编译到机器代码执行,机器码的执行性能已经非常之高,而这次引入字节码则是选择编译 JS 代码到一个中间态的字节码,执行时是解释执行,性能是低于机器代码的。最终的性能测试势必会降低,而不是提高。那么 V8 为什么要做这样一个退步的选择呢?为 V8 引入字节码的动机又是什么呢?笔者总结下来有三条:...
Part11 Chrome页面的绘制(绘制,就是把一个HTML文件变成一个活灵活现的页面展示的过程…),只有一半轮子是Chrome自己做的,还有一部分来自于WebKit,这个Apple打造的Web渲染器。。。 之所以说是一半轮子来源于WebKit,是因为WebKit本身包含两部分主要内容,一部分是做Html渲染的,另一部分是做JavaScript解析的。在Chrome中,只有Html的渲染采用了WebKit的代码,而在JavaScript上,重新搭建了一个NB哄哄的V8引擎。目标是,用WebKit + V8的强强联手,打造一款上网冲浪的法拉利,从效果来看,还着实做的不错。。。 不过,虽说Chrome和WebKit都是开源的,并联手工作。但是,Chrome还是刻意的和WebKit保持了距离,为其始乱终弃埋下了伏笔。Chrome在WebKit上封装了一层,称为WebKit Glue。Glue层中,大部分类型的结构和接口都和WebKit类似,Chrome中依托WebKit的组件,都只是调用WebKit Glue层的接口,而不是直接调用WebKit中的类型。按照Chrome自己文档中的话来说,就是,虽然我们再用WebKit实现页面的渲染,但通过这个设计(加一个间接层…)已经从某种程度大大降低了与WebKit的耦合,使得可以很容易将WebKit换成某个未来可能出现的更好的渲染引擎。。。 Part22 我们知道不同浏览器用的不同的渲染引擎: Tridend(IE)、Gecko(FF)、WebKit(Safari,Chrome,Andriod浏览器) 当然 Chrome 重构了一下 WebKit 然后管它叫 Blink。但是大体架构还是和 WebKit 一致的。 我们看看我们常说的 V8 和 WebKit 有什么关系吧。 下面是 WebKit 的大致结构: 实线框内模块是所有移植的共有部分,虚线框内不同的厂商可以自己实现。 就是说 JS 引擎(JS 虚拟机),WebKit 是默认的是 JSCore,而 Google 则自己实现了一版吊炸天的 V8。 因此虽然同样是WebKit,Safari 用的是 JSCore, Chrome 用的是 V8。 v8与webkit的关系 ↩︎ webkit vs v8 ↩︎
记录一下 安装依赖 apt install -y gettext build-essential autoconf pkg-config libtool libpcre3-dev asciidoc xmlto libev-dev libc-ares-dev automake libmbedtls-dev libsodium-dev 下载代码 git clone https://github.com/shadowsocks/shadowsocks-libev.git cd shadowsocks-libev git submodule update --init --recursive //下载子模块 编译 ./autogen.sh ./configure make && make install