>>>【说明】还是一如既往的,这篇文章是从我的个人博客里挪过来的。原文参见:http://www.jscon.co/coding/frontend/nodejs_fork_child_process.html

Child Process模块还提供一个用于创建一个也是Node.js的子进程,并提供父子进程具备通信通道的能力,这个方法称为 fork() ,相当于spawn('node', ['./child.js'])。与默认的spawn不同的是,fork会在父进程与子进程直接建立一个 IPC管道 ,用于父子进程之间的通信。
         使用 fork() 的开销在于每个子进程是个全新的V8实例,Node.js文档提到,每一个进程需要花费30ms 启动并占用 10MB 内存,所以能启动多少个子进程取决于计算机有多少内存。

1、一个例子

【举例】现在我们模拟Boss向职员分配任务的过程。情景是这样的:Boss现在有三个任务让三个职员去做,一个负责一个。这三个职员不能并行处理这三个任务,只有当完成一个任务后,Boss才会分配给另外一个职员下一个任务。

(苦逼码农:我的Boss向来让我一个人顶仨~~)

这里的Boss是父线程,职员是子线程。我们一步一步来完成这个情节的代码。

【注意】

fork函数有一个问题,就是它只能运行JavaScript代码,如果你喜欢用CoffeeScript(或者其他任何编译到js的语言),是无法通过fork调用的

文章《Node.js中的child_process及进程通信》提供了一种方法,不过我没有成功,大家可以试试:

一个简单的方法是把代码编译到JavaScript再运行,但是很不方便,有没有什么办法呢?

答案是可以的,还是得回到spawn函数。spawn函数除了接受command, args外,还接受一个options参数。通过把options参数的stdio设为['ipc'],即可在父子进程之间建立IPC管道。例如子进程使用CoffeeScript:

child_process = require('child_process')

options =

  stdio: ['ipc']

child = child_process.spawn 'coffee', ['./child.coffee'], options

因此下面的程序虽是用CoffeeScript编写的,但最后都编译成js文件再运行。

2、创建基础父子进程

CoffeeScript代码:

父进程所在文件:(removed.coffee)

fork = require("child_process").fork           # 引入fork组件

child = fork "child.js"                         # 生成child子进程

console.log "parent pid:",process.pid

child.on "message",(m)->              #定义父进程收到子进程发来消息时的动作

     console.log "receive message:",m

     setTimeout ()->

         child.kill "SIGINT"            #子进程完成任务了,过3秒后杀死child进程

     ,3000

child.on 'exit',(code,sig)->            #当子进程退出时所触发的动作

     console.log code,":",sig

child.send "task1"                    # OK,开始向子进程发送消息!

子进程所在文件:(child.coffee)

console.log "==========================="

console.log "child pid:",process.pid

process.on 'message',(m)->            #定义子进程收到父进程发来消息时的动作

     console.log process.pid,'start new task:',m

     console.log "start process.....Done"

     console.log "communiate with parent...."

     process.send "done"               #子进程完成任务后,向父进程汇报

上面的代码大部分是装饰形的log代码,其中有注释的代码才是关键的。 

代码解释:

上面的代码讲了这么一个故事:Boss通过fork生成一个子进程,给子进程喊了一句“task1”后,子进程就屁颠屁颠得去做任务。子进程完成后向父进程汇报“done”,父进程得知职员办事给力,一高兴,3秒钟之后kill了这个进程,然后,就没有然后了….

(这是在拍《风云》的节奏啊…..)

运行结果:

3、完成进程管理

上面的代码只生成了一个子进程,说好的三个呢?有了上面的基础代码,完成题目的要求就比较简单了,这次我们只稍微修改父进程所在的脚本即可:

CoffeeScript代码:

父进程所在文件:(removed.coffee)

fork = require("child_process").fork

child = fork "child.js"

console.log "parent pid:",process.pid

rebuild = (child)->                    # 将两个事件侦听器包装秤rebuild函数

     child.on "message",(m)->        

         console.log "receive message:",m

         setTimeout ()->

              child.kill "SIGINT"      # kill 子进程

              child = fork "child.js"   # 重生成子进程         

              rebuild(child)            # 给生成的子进程绑定侦听器

              child.send "task1"       # 父进程给子进程发消息

         ,3000           

     child.on 'exit',(code,sig)->

         console.log code,":",sig

rebuild(child)

child.send "task1"

代码解释:

       这是“稍微修改”的意思?果然呵,男人都是骗子!

通过现象看本质,看一下修改的步骤:

①  这里把前一部分的事件侦听器代码(就是那两个 on 什么的啦)包装了一下,命名成一个 rebuild函数 。这里的重点是然后再在递归使用。因为我们在每一次任务完成后会kill掉子进程,所以被kill掉的子进程的侦听器自然跟着消亡,所以每次fork之后就需要重新绑定事件(就是那两个 on 什么的啦):

                            child.kill "SIGINT"

                            child = fork "child.js"                         

                            rebuild(child)

                            child.send "task"+count

也许通过这四行代码你就会发现,俺家之所以将该函数取名为rebuild函数是有原因的:凤凰涅槃,浴火重生;第一句kill上次的child,接着fork一个新的child,同时rebuild出该新函数的事件侦听器(就是那两个 on 什么的啦),接着父元素有向这个新生的child发出“task1”信号….

②  猜想的出来执行之后的效果么?如果认为会出现刷屏代码的话,说明你已经懂了

运行结果:

[caption id="" align="aligncenter" width="397"] 无尽地循环执行任务 [/caption]

很明显上面的代码不是我们所想要的,我们只要三个子进程即可!好吧,杜绝超生,那只能计划生育了。加个count变量,加个 if… else… 语句就行了。不多说,翠花,上代码:

CoffeeScript代码:

父进程所在文件:(removed.js)

fork = require("child_process").fork

child = fork "child.js"

console.log "parent pid:",process.pid

count = 0

rebuild = (child)->

     child.on "message",(m)->

         count += 1

         if count < 3         

              console.log "receive message:",m

              setTimeout ()->

                   child.kill "SIGINT"

                   child = fork "child.js"                

                   rebuild(child)

                   child.send "task"+count

              ,3000

         else

              console.log "receive message:",m

              console.log "task over"

              setTimeout ()->

                   child.kill "SIGINT"

              ,3000           

     child.on 'exit',(code,sig)->

         console.log code,":",sig

rebuild(child)

child.send "task"+count

运行结果:

[caption id="" align="aligncenter" width="364"] 完成有限的进程管理[/caption]

4、传递参数

如果仅仅这样单纯的管理的话,父子进程(为啥我总打成“父子进城”呢??)其实不过尔尔,花拳绣腿罢了。一般的情形父进程往往会附带一些详细的指令给子进程,比如“去城里买些菜回来”~~

传递的message可以是JSON格式,真的是JSON,不骗你,不带解析的!

CoffeeScript代码:

父进程所在文件 removed.coffee 修改的地方较少,只有两处但很关键:

child.send "task"+count

改成:

child.send {where:"城市"+count,fn:"buy"}

没错,传送的就是JSON格式的数据。

子进程所在文件:(child.coffee)

console.log "==========================="

console.log "child pid:",process.pid

exports.buy = ()-> "买菜"              #定义buy函数

process.on 'message',(m)->             

     console.log process.pid,'start new task:',m

console.log "到",m.where,",",exports[m.fn]()   #字符串和函数

     console.log "start process.....Done"

     console.log "communiate with parent...."

     process.send "done"    

这里我想表达的意思有两个:

①  父子线程间的通信可以是JSON格式的,不用解析可以直接使用;

②  你看出来了么,“buy”是父进程传给子进程的一个字符串量,但在子进程中调用了其buy函数~~

运行结果:

[caption id="" align="aligncenter" width="454"] 进程通信中的传递参数[/caption]

故事的结尾,为了响应Boss的号召,这三个职员就真的去三个城市买菜,卖完菜后,Boss很十分感动, 就kill 它们了,然后,就没有然后了….

(汗…………………………………………………………….. The End)

【NodeJS线程】Boss和他的职员们的更多相关文章

  1. nodejs上传图片并显示的例子

    目标 1. 在浏览器地址栏输入“http://demos/start”,进入欢迎页面,页面有一个文件上传表单: 2. 选择一张图片并提交表单,文件被上传到"http://demos/uplo ...

  2. nodeJs学习过程之一个图片上传显示的例子

    目标 1. 在浏览器地址栏输入“http://demos/start”,进入欢迎页面,页面有一个文件上传表单: 2. 选择一张图片并提交表单,文件被上传到"http://demos/uplo ...

  3. Netty多线程处理机制

    技术点描述 本文主要研究NioServerSocketChannelFactory类和NioDatagramChannelFactory类, 以及这两个类的各自作用. 由于基于pipelineFact ...

  4. 一篇文章,读懂Netty的高性能架构之道

    一篇文章,读懂Netty的高性能架构之道 Netty是由JBOSS提供的一个java开源框架,是一个高性能.异步事件驱动的NIO框架,它提供了对TCP.UDP和文件传输的支持,作为一个异步NIO框架, ...

  5. netty12---线程池简单源码

    package com.cn; import java.io.IOException; import java.nio.channels.Selector; import java.util.Queu ...

  6. Netty框架原理

    用这张图表示的就是一个基本的Netty框架 通过创建两个线程池,一个负责接入, 一个负责处理 public class Start { public static void main(String[] ...

  7. DotNetty实现WebSocket的简单使用

    工作中项目是物联网项目的,管理平台又是bs架构. 如果用 Socket 的话,Web 端还需要转发,就全部统一采用了 WebSocket . DotNet 平台上的 WebSocket 实现有很多种, ...

  8. Nodejs事件引擎libuv源码剖析之:高效线程池(threadpool)的实现

    声明:本文为原创博文,转载请注明出处. Nodejs编程是全异步的,这就意味着我们不必每次都阻塞等待该次操作的结果,而事件完成(就绪)时会主动回调通知我们.在网络编程中,一般都是基于Reactor线程 ...

  9. (三)Netty源码学习笔记之boss线程处理流程

    尊重原创,转载注明出处,原文地址:http://www.cnblogs.com/cishengchongyan/p/6160194.html  本文我们将先从NioEventLoop开始来学习服务端的 ...

随机推荐

  1. MySQL 各种超时参数的含义

    MySQL 各种超时参数的含义 今日在查看锁超时的设置时,看到show variables like '%timeout%';语句输出结果中的十几种超时参数时突然想整理一下,不知道大家有没有想过,这么 ...

  2. cpu主频信息

    yangkunvanpersie ( yangkunvanpersie@163.com ) 通过"有道云笔记"邀请您查看以下笔记 修改CPU频率.note   打开笔记 kerne ...

  3. eclipse 4.5.2 源码修改 格式化Java代码

    注:本文代码基于eclipse4.5.2 1. 需求:在换电脑之后,如何不用配置eclipse就可以很快进入开发呢,并保持原来的编码规范. 2. 方法:修改eclipse源码 分别修改了两个jar包2 ...

  4. RStudio中,出现中文乱码问题的解决方案

    RStudio中,出现中文乱码问题的解决方案解决步骤:1.设置RStudio文本显示的默认编码:RStudio菜单栏的Tools -> Global Options2.选择General -&g ...

  5. HDU5795A Simple Nim SG定理

    A Simple Nim Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Tota ...

  6. ReportService未指定 OverwriteDataSources

    报表服务器部署好之后,查看报表就显示ConnectionString 属性尚未初始化. 然后重启部署并查看部署时控制台的输出信息,发现之前的部署成功消息是假象,实际上部署的时候有一个警告: 不能将数据 ...

  7. web前端之HTML的前世今生

    一个尖括号   < 一个尖括号能干什么    < ? 你可以编出一顶帽子  <(:-p 或一张笑脸    :-> 或诉说一份爱   <3 或者更直接一些 <!DOC ...

  8. lseek函数

    所有打开的文件都有一个当前文件偏移量(current file offset),以下简称为 cfo.cfo 通常是一个非负整数,用于表明文件开始处到文件当前位置的字节数.读写操作通常开始于 cfo,并 ...

  9. C#引用C++开发的DLL

    C#语言使用方便,入门门槛较代,上手容易,并且语法与C,java有很类似的地方,IDE做的也好,通用性好,是MS下一代开发的主要力量.但是其开源代码较少,类库不是十分完美,在架构方面还有一些需要做的工 ...

  10. 实验二 用C语言表示进程的调度

    实验二 一. 实验目的 通过模拟进程的调度,进一步了解进程的调度的具体过程. 二. 实验内容和要求 1.进程PCB的结构体定义 2.定义队列 3.输入进程序列 4.排序(按到位时间) 5.输出进程运行 ...