首先说一下nodejs单线程的优势:

高性能,与php相比,避免了频繁创建切换线程的开销,执行更加迅速,资源占用小。

线程安全,不用担心同一变量被多线程读写,造成程序崩溃。

单线程的异步和非阻塞,其实 nodejs底层访问I/O还是多线程的,阻塞/非阻塞与异步/同步是两个不同的概念,同步不代表阻塞,但是阻塞肯定就是同步;有点儿绕口,请听我举例,我去食堂打饭,我选择了A套餐,然后工作人员帮我去配餐,如果我就站在旁边,等待工作人员给我配餐,这种情况就称之为同步;若工作人员帮我配餐的同时,排在我后面的人就开始点餐,这样整个食堂的点餐服务并没有因为我在等待A套餐而停止,这种情况就称之为非阻塞。这个例子就简单说明了同步但非阻塞的情况。再如果我在等待配餐的时候去买饮料,等听到叫号再回去拿套餐,此时我的饮料也已经买好,这样我在等待配餐的同时还执行了买饮料的任务,叫号就等于执行了回调,就是异步非阻塞了。如果我在买饮料的时候,已经叫我的号让我去拿套餐,可是我等了好久才拿到饮料,所以我可能在大厅叫我的餐号之后很久才拿到A套餐,这也就是单线程的阻塞情况。

多线程:

线程是cpu调度的一个基本单位,一个cpu只能执行一个线程任务。

nodejs也可以执行多行程任务,例如引用TAGG/TAGG2模块,大家可以看一下我上一篇文章,里面有具体的使用方法。但是不论是tagg/tagg2都是利用pthread库和V8::Isolate类来实现js多线程功能的,根据规则我们在线程里执行的函数无法使用nodejs的核心api,例如fs,crypto模块,所以还是有很大的局限性。

多进程:

在支持html5的浏览器里,我们可以使用webworker来将一些耗时的计算丢入worker进程中执行,这样主进程就不会阻塞,用户也不会有卡顿的感觉。

这里我们需要利用nodejs的child_process模块,child_process提供了fork方法,可以启动一个nodejs文件,将它视作worker进程,worker 工作完毕后,会把结果send给主进程,然后worker自动退出,这样我们就利用了多进程解决了主线程阻塞的问题。

var express = require('express');
var fork = require('child_process').fork;
var app = express();
app.get('/', function(req, res){
var worker = fork('./work.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(7878);

我们通过express监听7878端口,对每个用户的请求都会去fork一个子进程,通过调用worker.send方法将参数n传递给子进程,同时监听子进程发送消息的message事件,将结果响应给客户端。

下面是被fork的work.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);
//计算jibo
process.send({type: 'fibo',result:num})
//计算完毕返回结果
}
});
process.on('SIGHUP', function() {
process.exit();//收到kill信息,进程退出
});

我们先定义函数fibo用来计算斐波那契数组,然后监听了主线程发来的消息,计算完毕之后将结果send到主线程。同时还监听process的SIGHUP事件,触发此事件就进程退出。

这里我们有一点需要注意,主线程的kill方法并不是真的使子进程退出,而是会触发子进程的SIGHUP事件,真正的退出还是依靠process.exit()。

总结:

使用child_process模块的fork方法确实可以让我们很好的解决单线程对cpu密集型任务的阻塞问题,同时又没有tagg包那样无法使用Node.js核心api的限制。

单线程异步的Node.js不代表不会阻塞,在主线程做过多的任务可能会导致主线程的卡死,影响整个程序的性能,所以我们要非常小心的处理大量的循环,字符串拼接和浮点运算等cpu密集型任务,合理的利用各种技术把任务丢给子线程或子进程去完成,保持Node.js主线程的畅通。

线程/进程的使用并不是没有开销的,尽可能减少创建和销毁线程/进程的次数,可以提升我们系统整体的性能和出错的概率。

Nodejs密集型CPU解决方案的更多相关文章

  1. Linux下高cpu解决方案(转载)

    Linux下高cpu解决方案(转载 1.用top命令查看哪个进程占用CPU高gateway网关进程14094占用CPU高达891%,这个数值是进程内各个线程占用CPU的累加值.   PID USER  ...

  2. Linux下高cpu解决方案

    昨天搞定了一个十万火急的issue,客户抱怨产品升级后系统会变慢和CPU使用率相当高,客户脾气很大,声称不尽快解决这个问题就退货,弄得我们 R&D压力很大,解决这个issue的任务分给了我,客 ...

  3. Linux下高cpu解决方案(转载)

    昨天搞定了一个十万火急的issue,客户抱怨产品升级后系统会变慢和CPU使用率相当高,客户脾气很大,声称不尽快解决这个问题就退货,弄得我们 R&D压力很大,解决这个issue的任务分给了我,客 ...

  4. [nodejs]npm国内npm安装nodejs modules终极解决方案

    此方案用于设置代理和修改镜像地址都不能解决问题使用 1.npm root 确认node模块的根文件夹,全局要加-g. osx同样是此命令,先清除缓存. npm cache clean C:\Users ...

  5. CPU密集型和I/O密集型区别

    CPU密集型 一些进程绝大多数时间在计算上,称为计算密集型(CPU密集型)computer-bound.一些大量循环的代码(例如:图片处理.视频编码.人工智能等)就是CPU密集型. I/O密集型 有一 ...

  6. Java多线程(二)关于多线程的CPU密集型和IO密集型这件事

    点我跳过黑哥的卑鄙广告行为,进入正文. Java多线程系列更新中~ 正式篇: Java多线程(一) 什么是线程 Java多线程(二)关于多线程的CPU密集型和IO密集型这件事 Java多线程(三)如何 ...

  7. CPU密集型 VS IO密集型

    CPU密集型 CPU密集型也叫计算密集型,指的是系统的硬盘.内存性能相对CPU要好很多,此时,系统运作大部分的状况是CPU Loading 100%,CPU要读/写I/O(硬盘/内存),I/O在很短的 ...

  8. python网络编程基础(线程与进程、并行与并发、同步与异步、阻塞与非阻塞、CPU密集型与IO密集型)

    python网络编程基础(线程与进程.并行与并发.同步与异步.阻塞与非阻塞.CPU密集型与IO密集型) 目录 线程与进程 并行与并发 同步与异步 阻塞与非阻塞 CPU密集型与IO密集型 线程与进程 进 ...

  9. 玩转nodeJS系列:使用cluster创建nodejs单机多核集群(多进程)

    前言: nodejs提供了cluster集群(支持端口共享的多进程),cluster基于child_process,process二次封装,方便我们使用该功能实现单机nodejs的web集群. 1.c ...

随机推荐

  1. ThinkPHP中的Model模型

    一     实例化模型对象 ①实例化通用模型 例:$goods_model = new \Model\GoodsModel(); $goods_Model = D('Goods'); ②实例化基例模型 ...

  2. c语言贪吃蛇详解1.画出地图

    c语言贪吃蛇详解-1.画出地图 前几天的实验室培训课后作业我布置了贪吃蛇,今天有时间就来写一下题解.我将分几步来教大家写一个贪吃蛇小游戏.由于大家c语言未学完,这个教程只涉及数组和函数等知识点. 首先 ...

  3. javaScript 验证码 倒计时60秒

    <input type="button" id="btn" value="免费获取验证码" /> <script type ...

  4. Ubuntu 14.4 Django模型迁移到数据库提示 LookupError: unknown encoding: utf8mb4 解决方法

    由于数据库中需要存储emoji表情,因此需要mysql支持utf8mb4,参考前面的文章升级数据库. 但是由于服务器上面的python-mysqldb连接包版本为1.2.3不支持utf8mb4,因此报 ...

  5. 是否是有效的dom节点--轮子代码

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"/> <title> ...

  6. ArrayList在foreach正常迭代删除不报错的原因

    一.背景 在以前的随笔中说道过ArrayList的foreach迭代删除的问题:ArrayList迭代过程删除问题 按照以前的说法,在ArrayList中通过foreach迭代删除会抛异常:java. ...

  7. javaweb:推断当前请求是否为移动设备訪问

    这段时间都是在做pc端的业务.结果经理找到我说,可能要做移动端的应用,后台逻辑还是用我写的逻辑.可是须要修改一些,看看怎么处理. 因为移动端和pc端还是略微有些差别的,我认为最好是在一个地儿统一推断, ...

  8. java 线程 捕获异常

    java 线程 捕获异常  来自:thinking in java 4 文件夹20.2.13 package org.rui.thread.concurrent; import java.util.c ...

  9. Struts2学习笔记整理(二)

    这里是重点. Action接口 struts2 的Action可以是POJO 为了让用户开发的Action更加规范struts2提供了一个Action接口 ActionSupport基类 Struts ...

  10. System.out.println()的解释

    上周面试的时候,面试官让我解释一下输出语句每一个单词是什么意思.当是有点蒙,后来想想这不就是考察对java中常用的的包,类和其中的方法的熟悉程度吗? 我们首先来看看System:这是一个类名,存在于j ...