当前位置: 首页 > news >正文

免费的行情软件网站入口中铁建设

免费的行情软件网站入口,中铁建设,我要软文网,织梦做的网站_别人提交给我留的言我去哪里看[From] http://www.admin10000.com/document/4196.html 前言 很多Node.js初学者都会有这样的疑惑#xff0c;Node.js到底是单线程的还是多线程的#xff1f;通过本章的学习#xff0c;能够让读者较为清晰的理解Node.js对于单/多线程的关系和支持情况。同时本章还将列举一些让…[From] http://www.admin10000.com/document/4196.html   前言   很多Node.js初学者都会有这样的疑惑Node.js到底是单线程的还是多线程的通过本章的学习能够让读者较为清晰的理解Node.js对于单/多线程的关系和支持情况。同时本章还将列举一些让Node.js的web服务器线程阻塞的例子最后会提供Node.js碰到这类cpu密集型问题的解决方案。   在学习本章之前读者需要对Node.js有一个初步的认识熟悉Node.js基本语法、cluster模块、child_process模块和express框架接触过apache的http压力测试工具ab了解一般web服务器对于静态文件的处理流程。  Node.js和PHP   早期有很多关于Node.js争论的焦点都在它的单线程模型方面在由Jani Hartikainen写的一篇著名的文章《PHP优于Node.js的五大理由》中更有一条矛头直接指向Node.js单线程脆弱的问题。 如果PHP代码损坏不会拖垮整个服务器。 PHP代码只运行在自己的进程范围中当某个请求显示错误时它只对特定的请求产生影响。而在Node.js环境中所有的请求均在单一的进程服务中当某个请求导致未知错误时整个服务器都会受到影响。   Node.js和ApachePHP还有一个非常不同的地方就是进程的运行时间长短当然这一点也被此文作为一个PHP优于Node.js的理由来写了。 PHP进程短暂。在PHP中每个进程对请求持续的时间很短暂这就意味着你不必为资源配置和内存而担忧。而Node.js的进程需要运行很长一段时间你需要小心并妥善管理好内存。比如如果你忘记从全局数据中删除条目这会轻易的导致内存泄露。   在这里我们并不想引起一次关于PHP和Node.js孰优孰劣的口水仗PHP和Node.js各代表着一个互联网时代的开发语言就如同我们讨论跑车和越野车谁更好一样它们都有自己所擅长和适用的场景。我们可以通过下面这两张图深入理解一下PHP和Node.js对处理Http请求时的区别。   PHP的模型   Node.js的模型   所以你在编写Node.js代码时要保持清醒的头脑任何一个隐藏着的异常被触发后都会将整个Node.js进程击溃。但是这样的特性也为我们编写代码带来便利比如同样要实现一个简单的网站访问次数统计Node.js只需要在内存里定义一个变量var count0;每次有用户请求过来执行count;即可。 var http require(http); var count 0; http.createServer(function (request, response) {response.writeHead(200, {Content-Type: text/plain});response.end((count).toString()) }).listen(8124); console.log(Server running at http://127.0.0.1:8124/);     但是对于PHP来说就需要使用第三方媒介来存储这个count值了比如创建一个count.txt文件来保存网站的访问次数。 ?php$counter_file (count.txt);$visits file($counter_file);$visits[0];$fp fopen($counter_file,w);fputs($fp,$visits[0]);fclose($fp);echo $visits[0]; ?    单线程的js   Google的V8 Javascript引擎已经在Chrome浏览器里证明了它的性能所以Node.js的作者Ryan Dahl选择了v8作为Node.js的执行引擎v8赋予Node.js高效性能的同时也注定了Node.js和大名鼎鼎的Nginx一样都是以单线程为基础的当然这也正是作者Ryan Dahl设计Node.js的初衷。  单线程的优缺点   Node.js的单线程具有它的优势但也并非十全十美在保持单线程模型的同时它是如何保证非阻塞的呢   高性能   首先单线程避免了传统PHP那样频繁创建、切换线程的开销使执行速度更加迅速。第二资源占用小如果有对Node.js的web服务器做过压力测试的朋友可能发现Node.js在大负荷下对内存占用仍然很低同样的负载PHP因为一个请求一个线程的模型将会占用大量的物理内存很可能会导致服务器因物理内存耗尽而频繁交换失去响应。   线程安全   单线程的js还保证了绝对的线程安全不用担心同一变量同时被多个线程进行读写而造成的程序崩溃。比如我们之前做的web访问统计因为单线程的绝对线程安全所以不可能存在同时对count变量进行读写的情况我们的统计代码就算是成百的并发用户请求都不会出现问题相较PHP的那种存文件记录访问就会面临并发同时写文件的问题。线程安全的同时也解放了开发人员免去了多线程编程中忘记对变量加锁或者解锁造成的悲剧。   单线程的异步和非阻塞   Node.js是单线程的但是它如何做到I/O的异步和非阻塞的呢其实Node.js在底层访问I/O还是多线程的有兴趣的朋友可以翻看Node.js的fs模块的源码里面会用到libuv来处理I/O所以在我们看来Node.js的代码就是非阻塞和异步形式的。   阻塞/非阻塞与异步/同步是两个不同的概念同步不代表阻塞但是阻塞肯定就是同步了。   举个现实生活中的例子我去食堂打饭我选择了A套餐然后工作人员帮我去配餐如果我就站在旁边等待工作人员给我配餐这种情况就称之为同步若工作人员帮我配餐的同时排在我后面的人就开始点餐这样整个食堂的点餐服务并没有因为我在等待A套餐而停止这种情况就称之为非阻塞。这个例子就简单说明了同步但非阻塞的情况。   再如果我在等待配餐的时候去买饮料等听到叫号再回去拿套餐此时我的饮料也已经买好这样我在等待配餐的同时还执行了买饮料的任务叫号就等于执行了回调就是异步非阻塞了。   阻塞的单线程   既然Node.js是单线程异步非阻塞的是不是我们就可以高枕无忧了呢   还是拿上面那个买套餐的例子如果我在买饮料的时候已经叫我的号让我去拿套餐可是我等了好久才拿到饮料所以我可能在大厅叫我的餐号之后很久才拿到A套餐这也就是单线程的阻塞情况。   在浏览器中js都是以单线程的方式运行的所以我们不用担心js同时执行带来的冲突问题这对于我们编码带来很多的便利。   但是对于在服务端执行的Node.js它可能每秒有上百个请求需要处理对于在浏览器端工作良好的单线程js是否也能同样在服务端表现良好呢   我们看如下代码 var start Date.now();//获取当前时间戳 setTimeout(function () {console.log(Date.now() - start);for (var i 0; i 1000000000; i){//执行长循环} }, 1000); setTimeout(function () {console.log(Date.now() - start); }, 2000);     最终我们的打印结果是结果可能因为你的机器而不同 1000 3738对于我们期望2秒后执行的setTimeout函数其实经过了3738毫秒之后才执行换而言之因为执行了一个很长的for循环所以我们整个Node.js主线程被阻塞了如果在我们处理100个用户请求中其中第一个有需要这样大量的计算那么其余99个就都会被延迟执行。   其实虽然Node.js可以处理数以千记的并发但是一个Node.js进程在某一时刻其实只是在处理一个请求。   单线程和多核   线程是cpu调度的一个基本单位一个cpu同时只能执行一个线程的任务同样一个线程任务也只能在一个cpu上执行所以如果你运行Node.js的机器是像i5i7这样多核cpu那么将无法充分利用多核cpu的性能来为Node.js服务。  多线程   在C、C#、python等其他语言都有与之对应的多线程编程有些时候这很有趣带给我们灵活的编程方式但是也可能带给我们一堆麻烦需要学习更多的Api知识在编写更多代码的同时也存在着更多的风险线程的切换和锁也会造成系统资源的开销。   就像上面的那个例子如果我们的Node.js有创建子线程的能力那问题就迎刃而解了 var start Date.now(); createThread(function () { //创建一个子线程执行这10亿次循环console.log(Date.now() - start);for (var i 0; i 1000000000; i){} }); setTimeout(function () { //因为10亿次循环是在子线程中执行的所以主线程不受影响console.log(Date.now() - start); }, 2000);     可惜也可以说可喜的是Node.js的核心模块并没有提供这样的api给我们我们真的不想多线程又回归回来。不过或许多线程真的能够解决我们某方面的问题。   tagg2模块   Jorge Chamorro Bieling是tagg(Threads a gogo for Node.js)包的作者他硬是利用phread库和C语言让Node.js支持了多线程的开发我们看一下tagg模块的简单示例 var Threads require(threads_a_gogo);//加载tagg包 function fibo(n) {//定义斐波那契数组计算函数return n 1 ? fibo(n - 1) fibo(n - 2) : 1; } var t Threads.create().eval(fibo); t.eval(fibo(35), function(err, result) {//将fibo(35)丢入子线程运行if (err) throw err; //线程创建失败console.log(fibo(35) result);//打印fibo执行35次的结果 }); console.log(not block);//打印信息了表示没有阻塞     上面这段代码利用tagg包将fibo(35)这个计算丢入了子线程中进行保证了Node.js主线程的舒畅当子线程任务执行完毕将会执行主线程的回调函数把结果打印到屏幕上执行结果如下 not block fibo(35)14930352斐波那契数列又称黄金分割数列这个数列从第三项开始每一项都等于前两项之和0、1、1、2、3、5、8、13、21、……。   注意我们上面代码的斐波那契数组算法并不是最优算法只是为了模拟cpu密集型计算任务。   由于tagg包目前只能在linux下安装运行所以我fork了一个分支修改了部分tagg包的代码发布了tagg2包。tagg2包同样具有tagg包的多线程功能采用新的node-gyp命令进行编译同时它跨平台支持maclinuxwindows下都可以使用对开发人员的api也更加友好。安装方法很简单直接npm install tagg2。   一个利用tagg2计算斐波那契数组的http服务器代码 var express require(express); var tagg2 require(tagg2); var app express(); var th_func function(){//线程执行函数以下内容会在线程中执行var fibo function fibo (n) {//在子线程中定义fibo函数return n 1 ? fibo(n - 1) fibo(n - 2) : 1;}var n fibo(~~thread.buffer);//执行fibo递归thread.end(n);//当线程执行完毕执行thread.end带上计算结果回调主线程 }; app.get(/, function(req, res){var n ~~req.query.n || 1;//获取用户请求参数var buf new Buffer(n.toString());tagg2.create(th_func, {buffer:buf}, function(err,result){//创建一个js线程,传入工作函数,buffer参数以及回调函数if(err) return res.end(err);//如果线程创建失败res.end(result.toString());//响应线程执行计算的结果}) }); app.listen(8124); console.log(listen on 8124);     其中~~req.query.n表示将用户传递的参数n取整功能类似Math.floor函数。   我们用express框架搭建了一个web服务器根据用户发送的参数n的值来创建子线程计算斐波那契数组当子线程计算完毕之后将结果响应给客户端。由于计算是丢入子线程中运行的所以整个主线程不会被阻塞还是能够继续处理新请求的。 我们利用apache的http压力测试工具ab来进行一次简单的压力测试看看执行斐波那契数组35次100客户端并发100个请求我们的QPS (Query Per Second)每秒查询率在多少。 ab的全称是ApacheBench是Apache附带的一个小工具用于进行HTTP服务器的性能测试可以同时模拟多个并发请求。   我们的测试硬件linux 2.6.4 4cpu 8G 64bit网络环境则是内网。   ab压力测试命令 ab -c 100 -n 100 http://192.168.28.5:8124/?n35压力测试结果 Server Software: Server Hostname: 192.168.28.5 Server Port: 8124Document Path: /?n35 Document Length: 8 bytesConcurrency Level: 100 Time taken for tests: 5.606 seconds Complete requests: 100 Failed requests: 0 Write errors: 0 Total transferred: 10600 bytes HTML transferred: 800 bytes Requests per second: 17.84 [#/sec](mean) Time per request: 5605.769 [ms](mean) Time per request: 56.058 [ms](mean, across all concurrent requests) Transfer rate: 1.85 [Kbytes/sec] receivedConnection Times (ms)min mean[/-sd] median max Connect: 3 4 0.8 4 6 Processing: 455 5367 599.7 5526 5598 Waiting: 454 5367 599.7 5526 5598 Total: 461 5372 599.3 5531 5602Percentage of the requests served within a certain time (ms)50% 553166% 556575% 557780% 558190% 559295% 559798% 560099% 5602100% 5602 (longest request)     我们看到Requests per second表示每秒我们服务器处理的任务数量这里是17.84。第二个我们比较关心的是两个Time per request结果上面一行Time per request:5605.769 [ms](mean)表示当前这个并发量下处理每组请求的时间而下面这个Time per request:56.058 [ms](mean, across all concurrent requests)表示每个用户平均处理时间因为我们本次测试并发是100所以结果正好是上一行的100分之1。得出本次测试平均每个用户请求的平均等待时间为56.058 [ms]。   另外我们看下最后带有百分比的列表可以看到50%的用户是在5531 ms以内返回的最慢的也不过5602 ms响应延迟非常的平均。   我们如果用cluster来启动4个进程是否可以充分利用cpu达到tagg2那样的QPS呢我们在同样的网络环境和测试机上运行如下代码 var cluster require(cluster);//加载clustr模块 var numCPUs require(os).cpus().length;//设定启动进程数为cpu个数 if (cluster.isMaster) {for (var i 0; i numCPUs; i) {cluster.fork();//启动子进程} } else {var express require(express);var app express();var fibo function fibo (n) {//定义斐波那契数组算法return n 1 ? fibo(n - 1) fibo(n - 2) : 1;}app.get(/, function(req, res){var n fibo(~~req.query.n || 1);//接收参数res.send(n.toString());});app.listen(8124);console.log(listen on 8124); }     在终端屏幕上打印了4行信息 listen on 8124 listen on 8124 listen on 8124 listen on 8124我们成功启动了4个cluster之后用同样的ab压力测试命令对8124端口进行测试结果如下 Server Software: Server Hostname: 192.168.28.5 Server Port: 8124Document Path: /?n35 Document Length: 8 bytesConcurrency Level: 100 Time taken for tests: 10.509 seconds Complete requests: 100 Failed requests: 0 Write errors: 0 Total transferred: 16500 bytes HTML transferred: 800 bytes Requests per second: 9.52 [#/sec](mean) Time per request: 10508.755 [ms](mean) Time per request: 105.088 [ms](mean, across all concurrent requests) Transfer rate: 1.53 [Kbytes/sec] receivedConnection Times (ms)min mean[/-sd] median max Connect: 4 5 0.4 5 6 Processing: 336 3539 2639.8 2929 10499 Waiting: 335 3539 2639.9 2929 10499 Total: 340 3544 2640.0 2934 10504Percentage of the requests served within a certain time (ms)50% 293466% 376375% 452780% 515390% 826195% 971998% 1030899% 10504100% 10504 (longest request)     通过和上面tagg2包的测试结果对比我们发现区别很大。首先每秒处理的任务数从17.84 [#/sec]下降到了9.52 [#/sec]这说明我们web服务器整体的吞吐率下降了然后每个用户请求的平均等待时间也从56.058 [ms]提高到了105.088 [ms]用户等待的时间也更长了。   最后我们发现用户请求处理的时长非常的不均匀50%的用户在2934 ms内返回了最慢的等待达到了10504 ms。虽然我们使用了cluster启动了4个Node.js进程处理用户请求但是对于每个Node.js进程来说还是单线程的所以当有4个用户跑满了4个Node.js的cluster进程之后新来的用户请求就只能等待了最后造成了先到的用户处理时间短后到的用户请求处理时间比较长就造成了用户等待时间非常的不平均。   v8引擎   大家看到这里是不是开始心潮澎湃感觉js一统江湖的时代来临了单线程异步非阻塞的模型可以胜任大并发同时开发也非常高效多线程下的js可以承担cpu密集型任务不会有主线程阻塞而引起的性能问题。   但是不论tagg还是tagg2包都是利用phtread库和v8的v8::Isolate Class类来实现js多线程功能的。 Isolate代表着一个独立的v8引擎实例v8的Isolate拥有完全分开的状态在一个Isolate实例中的对象不能够在另外一个Isolate实例中使用。嵌入式开发者可以在其他线程创建一些额外的Isolate实例并行运行。在任何时刻一个Isolate实例只能够被一个线程进行访问可以利用加锁/解锁进行同步操作。   换而言之我们在进行v8的嵌入式开发时无法在多线程中访问js变量这条规则将直接导致我们之前的tagg2里面线程执行的函数无法使用Node.js的核心api比如fscrypto等模块。如此看来tagg2包还是有它使用的局限性针对一些可以使用js原生的大量计算或循环可以使用tagg2Node.js核心api因为无法从主线程共享对象的关系也就不能跨线程使用了。   libuv   最后如果我们非要让Node.js支持多线程还是提倡使用官方的做法利用libuv库来实现。 libuv是一个跨平台的异步I/O库它主要用于Node.js的开发同时他也被Mozillas Rust language, Luvit, Julia, pyuv等使用。它主要包括了Event loops事件循环Filesystem文件系统Networking网络支持Threads线程Processes进程Utilities其他工具。   在Node.js核心api中的异步多线程大多是使用libuv来实现的下一章将带领大家开发一个让Node.js支持多线程并基于libuv的Node.js包。  多进程   在支持html5的浏览器里我们可以使用webworker来将一些耗时的计算丢入worker进程中执行这样主进程就不会阻塞用户也就不会有卡顿的感觉了。在Node.js中是否也可以使用这类技术保证主线程的通畅呢   cluster   cluster可以用来让Node.js充分利用多核cpu的性能同时也可以让Node.js程序更加健壮官网上的cluster示例已经告诉我们如何重新启动一个因为异常而奔溃的子进程。   webworker   想要像在浏览器端那样启动worker进程我们需要利用Node.js核心api里的child_process模块。child_process模块提供了fork的方法可以启动一个Node.js文件将它作为worker进程当worker进程工作完毕把结果通过send方法传递给主进程然后自动退出这样我们就利用了多进程来解决主线程阻塞的问题。   我们先启动一个web服务还是接收参数计算斐波那契数组 var express require(express); var fork require(child_process).fork; var app express(); app.get(/, function(req, res){var worker fork(./work_fibo.js) //创建一个工作进程worker.on(message, function(m) {//接收工作进程计算结果if(object typeof m m.type fibo){worker.kill();//发送杀死进程的信号res.send(m.result.toString());//将结果返回客户端}});worker.send({type:fibo,num:~~req.query.n || 1});//发送给工作进程计算fibo的数量 }); app.listen(8124);     我们通过express监听8124端口对每个用户的请求都会去fork一个子进程通过调用worker.send方法将参数n传递给子进程同时监听子进程发送消息的message事件将结果响应给客户端。   下面是被fork的work_fibo.js文件内容 var fibo function fibo (n) {//定义算法return n 1 ? fibo(n - 1) fibo(n - 2) : 1; } process.on(message, function(m) { //接收主进程发送过来的消息if(typeof m object m.type fibo){var num fibo(~~m.num);//计算jiboprocess.send({type: fibo,result:num})//计算完毕返回结果 } }); process.on(SIGHUP, function() {process.exit();//收到kill信息进程退出 });     我们先定义函数fibo用来计算斐波那契数组然后监听了主线程发来的消息计算完毕之后将结果send到主线程。同时还监听process的SIGHUP事件触发此事件就进程退出。   这里我们有一点需要注意主线程的kill方法并不是真的使子进程退出而是会触发子进程的SIGHUP事件真正的退出还是依靠process.exit();。   下面我们用ab 命令测试一下多进程方案的处理性能和用户请求延迟测试环境不变还是100个并发100次请求计算斐波那切数组第35位: Server Software: Server Hostname: 192.168.28.5 Server Port: 8124Document Path: /?n35 Document Length: 8 bytesConcurrency Level: 100 Time taken for tests: 7.036 seconds Complete requests: 100 Failed requests: 0 Write errors: 0 Total transferred: 16500 bytes HTML transferred: 800 bytes Requests per second: 14.21 [#/sec](mean) Time per request: 7035.775 [ms](mean) Time per request: 70.358 [ms](mean, across all concurrent requests) Transfer rate: 2.29 [Kbytes/sec] receivedConnection Times (ms)min mean[/-sd] median max Connect: 4 4 0.2 4 5 Processing: 4269 5855 970.3 6132 7027 Waiting: 4269 5855 970.3 6132 7027 Total: 4273 5860 970.3 6136 7032Percentage of the requests served within a certain time (ms)50% 613666% 656175% 678180% 685790% 696895% 700398% 701799% 7032100% 7032 (longest request)     压力测试结果QPS约为14.21,相比cluster来说还是快了很多每个用户请求的延迟都很平均因为进程的创建和销毁的开销要大于线程所以在性能方面略低于tagg2不过相对于cluster方案这样的提升还是令我们满意的。   换一种思路   使用child_process模块的fork方法确实可以让我们很好的解决单线程对cpu密集型任务的阻塞问题同时又没有tagg2包那样无法使用Node.js核心api的限制。   但是如果我的worker具有多样性每次在利用child_process模块解决问题时都需要去创建一个worker.js的工作函数文件有点麻烦。我们是不是可以更加简单一些呢   在我们启动Node.js程序时node命令可以带上-e这个参数它将直接执行-e后面的字符串如下代码就将打印出hello world。 node -e console.log(hello world)合理的利用这个特性我们就可以免去每次都创建一个文件的麻烦。 var express require(express); var spawn require(child_process).spawn; var app express(); var spawn_worker function(n,end){//定义工作函数var fibo function fibo (n) {return n 1 ? fibo(n - 1) fibo(n - 2) : 1;}end(fibo(n));} var spawn_end function(result){//定义工作函数结束的回调函数参数console.log(result);process.exit(); } app.get(/, function(req, res){var n ~~req.query.n || 1;//拼接-e后面的参数var spawn_cmd (spawn_worker.toString()(n,spawn_end.toString()));console.log(spawn_cmd);//注意这个打印结果var worker spawn(node,[-e,spawn_cmd]);//执行node -e xxx命令var fibo_res ;worker.stdout.on(data, function (data) { //接收工作函数的返回fibo_res data.toString();});worker.on(close, function (code) {//将结果响应给客户端res.send(fibo_res);}); }); app.listen(8124);     代码很简单我们主要关注3个地方。   第一、我们定义了spawn_worker函数他其实就是将会在-e后面执行的工作函数所以我们把计算斐波那契数组的算法定义在内spawn_worker函数接收2个参数第一个参数n表示客户请求要计算的斐波那契数组的位数第二个end参数是一个函数如果计算完毕则执行end将结果传回主线程   第二、真正当Node.js脚步执行的字符串其实就是spawn_cmd里的内容它的内容我们通过运行之后的打印信息很容易就能明白   第三、我们利用child_process的spawn方法类似在命令行里执行了node -e js code启动Node.js工作进程同时监听子进程的标准输出将数据保存起来当子进程退出之后把结果响应给用户。   现在主要的焦点就是变量spawn_cmd到底保存了什么我们打开浏览器在地址栏里输入 http://127.0.0.1:8124/?n35下面就是程序运行之后的打印信息 (function (n,end){var fibo function fibo (n) {return n 1 ? fibo(n - 1) fibo(n - 2) : 1;}end(fibo(n));}(35,function (result){console.log(result);process.exit(); }));     对于在子进程执行的工作函数的两个参数n和end现在一目了然n代表着用户请求的参数期望获得的斐波那契数组的位数而end参数则是一个匿名函数在标准输出中打印计算结果然后退出进程。   node -e命令虽然可以减少创建文件的麻烦但同时它也有命令行长度的限制这个值各个系统都不相同我们通过命令getconf ARG_MAX来获得最大命令长度例如MAC OSX下是262,144 byte而我的linux虚拟机则是131072 byte。  多进程和多线程   大部分多线程解决cpu密集型任务的方案都可以用我们之前讨论的多进程方案来替代但是有一些比较特殊的场景多线程的优势就发挥出来了下面就拿我们最常见的http web服务器响应一个小的静态文件作为例子。   以express处理小型静态文件为例大致的处理流程如下 1、首先获取文件状态判断文件的修改时间或者判断etag来确定是否响应304给客户端让客户端继续使用本地缓存。 2、如果缓存已经失效或者客户端没有缓存就需要获取文件的内容到buffer中为响应作准备。 3、然后判断文件的MIME类型如果是类似htmljscss等静态资源还需要gzip压缩之后传输给客户端 4、最后将gzip压缩完成的静态文件响应给客户端。   下面是一个正常成功的Node.js处理静态资源无缓存流程图   这个流程中的(2)(3)(4)步都经历了从js到C 打开和释放文件还有调用了zlib库的gzip算法其中每个异步的算法都会有创建和销毁线程的开销所以这样也是大家诟病Node.js处理静态文件不给力的原因之一。   为了改善这个问题我之前有利用libuv库开发了一个改善Node.js的http/https处理静态文件的包名为ifileifile包之所以可以加速Node.js的静态文件处理性能主要是减少了js和C的互相调用以及频繁的创建和销毁线程的开销下图是ifile包处理一个静态无缓存资源的流程图   由于全部工作都是在libuv的子线程中执行的所以Node.js主线程不会阻塞当然性能也会大幅提升了使用ifile包非常简单它能够和express无缝的对接。 var express require(express); var ifile require(ifile); var app express(); app.use(ifile.connect()); //默认值是 [[/static,__dirname]]; app.listen(8124);     上面这4行代码就可以让express把静态资源交给ifile包来处理了我们在这里对它进行了一个简单的压力测试测试用例为响应一个大小为92kb的jquery.1.7.1.min.js文件测试命令 ab -c 500 -n 5000 -H Accept-Encoding: gzip http://192.168.28.5:8124/static/jquery.1.7.1.min.js由于在ab命令中我们加入了-H Accept-Encoding: gzip表示响应的静态文件希望是gzip压缩之后的所以ifile将会把压缩之后的jquery.1.7.1.min.js文件响应给客户端。结果如下 Server Software: Server Hostname: 192.168.28.5 Server Port: 8124Document Path: /static/jquery.1.7.1.min.js Document Length: 33016 bytesConcurrency Level: 500 Time taken for tests: 9.222 seconds Complete requests: 5000 Failed requests: 0 Write errors: 0 Total transferred: 166495000 bytes HTML transferred: 165080000 bytes Requests per second: 542.16 [#/sec](mean) Time per request: 922.232 [ms](mean) Time per request: 1.844 [ms](mean, across all concurrent requests) Transfer rate: 17630.35 [Kbytes/sec] receivedConnection Times (ms)min mean[/-sd] median max Connect: 0 49 210.2 1 1003 Processing: 191 829 128.6 870 1367 Waiting: 150 824 128.5 869 1091 Total: 221 878 230.7 873 1921Percentage of the requests served within a certain time (ms)50% 87366% 87875% 88180% 88590% 91895% 110998% 181599% 1875100% 1921 (longest request)     我们首先看到Document Length一项结果为33016 bytes说明我们的jquery文件已经被成功的gzip压缩因为源文件大小是92kb其次我们最关心的Requests per second:542.16 [#/sec](mean)说明我们每秒能处理542个任务最后我们看到在这样的压力情况下平均每个用户的延迟在1.844 [ms]。   我们看下使用express框架处理这样的压力会是什么样的结果express测试代码如下 var express require(express); var app express(); app.use(express.compress());//支持gzip app.use(/static, express.static(__dirname /static)); app.listen(8124);     代码同样非常简单注意这里我们使用 app.use(/static, express.static(__dirname /static));而不是 app.use(express.static(__dirname));后者每个请求都会去匹配一次文件是否存在而前者只有请求url是/static开头的才会去匹配静态资源所以前者效率更高一些。然后我们执行相同的ab压力测试命令看下结果 Server Software: Server Hostname: 192.168.28.5 Server Port: 8124Document Path: /static/jquery.1.7.1.min.js Document Length: 33064 bytesConcurrency Level: 500 Time taken for tests: 16.665 seconds Complete requests: 5000 Failed requests: 0 Write errors: 0 Total transferred: 166890000 bytes HTML transferred: 165320000 bytes Requests per second: 300.03 [#/sec](mean) Time per request: 1666.517 [ms](mean) Time per request: 3.333 [ms](mean, across all concurrent requests) Transfer rate: 9779.59 [Kbytes/sec] receivedConnection Times (ms)min mean[/-sd] median max Connect: 0 173 539.8 1 7003 Processing: 509 886 350.5 809 9366 Waiting: 238 476 277.9 426 9361 Total: 510 1059 632.9 825 9367Percentage of the requests served within a certain time (ms)50% 82566% 90875% 120180% 144690% 182095% 195298% 256099% 3737100% 9367 (longest request)     同样分析一下结果Document Length:33064 bytes表示文档大小为33064 bytes说明我们的gzip起作用了每秒处理任务数从ifile包的542下降到了300最长用户等待时间也延长到了9367 ms可见我们的努力起到了立竿见影的作用js和C互相调用以及线程的创建和释放并不是没有损耗的。   但是当我在express的谷歌论坛里贴上这些测试结果并宣传ifile包的时候express的作者TJ给出了不一样的评价他在回复中说道 请牢记你可能不需要这么高等级吞吐率的系统就算是每月百万级别下载量的npm网站也仅仅每秒处理17个请求而已这样的压力甚至于PHP也可以处理掉又黑了一把php。   确实如TJ所说性能只是我们项目的指标之一而非全部一味的去追求高性能并不是很理智。   ifile包开源项目地址https://github.com/DoubleSpout/ifile  总结   单线程的Node.js给我们编码带来了太多的便利和乐趣我们应该时刻保持清醒的头脑在写Node.js代码中切不可与PHP混淆任何一个隐藏的问题都可能击溃整个线上正在运行的Node.js程序。   单线程异步的Node.js不代表不会阻塞在主线程做过多的任务可能会导致主线程的卡死影响整个程序的性能所以我们要非常小心的处理大量的循环字符串拼接和浮点运算等cpu密集型任务合理的利用各种技术把任务丢给子线程或子进程去完成保持Node.js主线程的畅通。   线程/进程的使用并不是没有开销的尽可能减少创建和销毁线程/进程的次数可以提升我们系统整体的性能和出错的概率。   最后请不要一味的追求高性能和高并发因为我们可能不需要系统具有那么大的吞吐率。高效敏捷低成本的开发才是项目所需要的这也是为什么Node.js能够在众多开发语言中脱颖而出的关键。  参考文献 http://smashingnode.com Smashing Node.JS By Guillermo Rauchhttp://bjouhier.wordpress.com/2012/03/11/fibers-and-threads-in-node-js-what-for Fibers and Threads in node.js – what for? By Brunos Ramblingshttps://github.com/xk/node-threads-a-gogo TAGG: Threads à gogo for Node.js By Jorge Chamorro Bielinghttps://code.google.com/p/v8/ Google v8https://github.com/joyent/libuv libuv by joyent转载于:https://www.cnblogs.com/pekkle/p/7920337.html
http://www.sadfv.cn/news/149296/

相关文章:

  • 建邺做网站价格网站建设 招聘
  • 企业网站建设的类型有哪些想做设计师需要学什么
  • 北京做兼职网站网站建设滨江
  • wordpress 资源站点做商城网站合作合同
  • 成都优秀网站建设网站开发维护的好处
  • 自学网站建设最快要多久网络工程师都考什么
  • 制作网站教程福建省建设工程监理协会网站
  • 做网页建网站挣钱关键词搜索点击软件
  • 网站建设如何运营企业做网站大概多少钱
  • 做视频类网站需要哪些许可全屏响应式网站建设
  • 东莞东城网站建设网站设计开发文档模板下载
  • 周口市住房和城乡建设局门户网站官方静态网站模板
  • 江苏网站建设找哪家潍坊公司网站建设
  • wordpress for sae图床哈尔滨网站优化咨询
  • 望京做网站的公司哪家好购物商城类app开发
  • 如何做网站品类网站建设招聘网
  • 西安做网站比较好的公司wordpress 安装php
  • 洛阳专业做网站多少钱网站设计会计分录怎么做
  • 网站建设的3个基本原则网站访问量大怎么办
  • 有没有网站果洛营销网站建设哪家好
  • iis发布网站乱码福州h5建站
  • 几大网站类型网站链接到邮箱怎么做
  • 兰州高端网站广州人社app怎么下载
  • 网站动态页面打不开工商注册核名查询官网
  • 搭建一个网站花多少钱做网站实例教程
  • 网站建设属于软件开发网页设计培训学校
  • 建设个人网站的参考网站及文献如何设计一个公司的网页
  • 有什么网站可以接淘宝设计单做做网站要哪些人员
  • 菏泽地网站seo电子商务专升本需要考些什么科目
  • 盘锦做网站公司建设公司网站意义