`
since1027
  • 浏览: 9781 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

5.进程管理

 
阅读更多

5.进程管理

NodeJS可以感知和控制自身进程的运行环境和状态,也可以创建子进程并与其协同工作,这使得NodeJS可以把多个程序组合在一起共同完成某项工作,并在其中充当胶水和调度器的作用。本章除了介绍与之相关的NodeJS内置模块外,还会重点介绍典型的使用场景。

开门红

我们已经知道了NodeJS自带的fs模块比较基础,把一个目录里的所有文件和子目录都拷贝到另一个目录里需要写不少代码。另外我们也知道,终端下的cp命令比较好用,一条cp -r source/* target命令就能搞定目录拷贝。那我们首先看看如何使用NodeJS调用终端命令来简化目录拷贝,示例代码如下:

var child_process = require('child_process');
var util = require('util');

function copy(source, target, callback) {
    child_process.exec(
        util.format('cp -r %s/* %s', source, target), callback);
}

copy('a', 'b', function (err) {
    // ...
});
 

从以上代码中可以看到,子进程是异步运行的,通过回调函数返回执行结果。

API走马观花

我们先大致看看NodeJS提供了哪些和进程管理有关的API。这里并不逐一介绍每个API的使用方法,官方文档已经做得很好了。

Process

官方文档: http://nodejs.org/api/process.html

任何一个进程都有启动进程时使用的命令行参数,有标准输入标准输出,有运行权限,有运行环境和运行状态。在NodeJS中,可以通过process对象感知和控制NodeJS自身进程的方方面面。另外需要注意的是,process不是内置模块,而是一个全局对象,因此在任何地方都可以直接使用。

Child Process

官方文档: http://nodejs.org/api/child_process.html

使用child_process模块可以创建和控制子进程。该模块提供的API中最核心的是.spawn,其余API都是针对特定使用场景对它的进一步封装,算是一种语法糖。

Cluster

官方文档: http://nodejs.org/api/cluster.html

cluster模块是对child_process模块的进一步封装,专用于解决单进程NodeJS Web服务器无法充分利用多核CPU的问题。使用该模块可以简化多进程服务器程序的开发,让每个核上运行一个工作进程,并统一通过主进程监听端口和分发请求。

应用场景

和进程管理相关的API单独介绍起来比较枯燥,因此这里从一些典型的应用场景出发,分别介绍一些重要API的使用方法。

如何获取命令行参数

在NodeJS中可以通过process.argv获取命令行参数。但是比较意外的是,node执行程序路径和主模块文件路径固定占据了argv[0]argv[1]两个位置,而第一个命令行参数从argv[2]开始。为了让argv使用起来更加自然,可以按照以下方式处理。

function main(argv) {
    // ...
}

main(process.argv.slice(2));
 

如何退出程序

通常一个程序做完所有事情后就正常退出了,这时程序的退出状态码为0。或者一个程序运行时发生了异常后就挂了,这时程序的退出状态码不等于0。如果我们在代码中捕获了某个异常,但是觉得程序不应该继续运行下去,需要立即退出,并且需要把退出状态码设置为指定数字,比如1,就可以按照以下方式:

try {
    // ...
} catch (err) {
    // ...
    process.exit(1);
}
 

如何控制输入输出

NodeJS程序的标准输入流(stdin)、一个标准输出流(stdout)、一个标准错误流(stderr)分别对应process.stdinprocess.stdoutprocess.stderr,第一个是只读数据流,后边两个是只写数据流,对它们的操作按照对数据流的操作方式即可。例如,console.log可以按照以下方式实现。

function log() {
    process.stdout.write(
        util.format.apply(util, arguments) + '\n');
}
 

如何降权

在Linux系统下,我们知道需要使用root权限才能监听1024以下端口。但是一旦完成端口监听后,继续让程序运行在root权限下存在安全隐患,因此最好能把权限降下来。以下是这样一个例子。

http.createServer(callback).listen(80, function () {
    var env = process.env,
        uid = parseInt(env['SUDO_UID'] || process.getuid(), 10),
        gid = parseInt(env['SUDO_GID'] || process.getgid(), 10);

    process.setgid(gid);
    process.setuid(uid);
});
 

上例中有几点需要注意:

  1. 如果是通过sudo获取root权限的,运行程序的用户的UID和GID保存在环境变量SUDO_UIDSUDO_GID里边。如果是通过chmod +s方式获取root权限的,运行程序的用户的UID和GID可直接通过process.getuidprocess.getgid方法获取。

  2. process.setuidprocess.setgid方法只接受number类型的参数。

  3. 降权时必须先降GID再降UID,否则顺序反过来的话就没权限更改程序的GID了。

如何创建子进程

以下是一个创建NodeJS子进程的例子。

var child = child_process.spawn('node', [ 'xxx.js' ]);

child.stdout.on('data', function (data) {
    console.log('stdout: ' + data);
});

child.stderr.on('data', function (data) {
    console.log('stderr: ' + data);
});

child.on('close', function (code) {
    console.log('child process exited with code ' + code);
});
 

上例中使用了.spawn(exec, args, options)方法,该方法支持三个参数。第一个参数是执行文件路径,可以是执行文件的相对或绝对路径,也可以是根据PATH环境变量能找到的执行文件名。第二个参数中,数组中的每个成员都按顺序对应一个命令行参数。第三个参数可选,用于配置子进程的执行环境与行为。

另外,上例中虽然通过子进程对象的.stdout.stderr访问子进程的输出,但通过options.stdio字段的不同配置,可以将子进程的输入输出重定向到任何数据流上,或者让子进程共享父进程的标准输入输出流,或者直接忽略子进程的输入输出。

进程间如何通讯

在Linux系统下,进程之间可以通过信号互相通信。以下是一个例子。

/* parent.js */
var child = child_process.spawn('node', [ 'child.js' ]);

child.kill('SIGTERM');

/* child.js */
process.on('SIGTERM', function () {
    cleanUp();
    process.exit(0);
});
 

在上例中,父进程通过.kill方法向子进程发送SIGTERM信号,子进程监听process对象的SIGTERM事件响应信号。不要被.kill方法的名称迷惑了,该方法本质上是用来给进程发送信号的,进程收到信号后具体要做啥,完全取决于信号的种类和进程自身的代码。

另外,如果父子进程都是NodeJS进程,就可以通过IPC(进程间通讯)双向传递数据。以下是一个例子。

/* parent.js */
var child = child_process.spawn('node', [ 'child.js' ], {
        stdio: [ 0, 1, 2, 'ipc' ]
    });

child.on('message', function (msg) {
    console.log(msg);
});

child.send({ hello: 'hello' });

/* child.js */
process.on('message', function (msg) {
    msg.hello = msg.hello.toUpperCase();
    process.send(msg);
});
 

可以看到,父进程在创建子进程时,在options.stdio字段中通过ipc开启了一条IPC通道,之后就可以监听子进程对象的message事件接收来自子进程的消息,并通过.send方法给子进程发送消息。在子进程这边,可以在process对象上监听message事件接收来自父进程的消息,并通过.send方法向父进程发送消息。数据在传递过程中,会先在发送端使用JSON.stringify方法序列化,再在接收端使用JSON.parse方法反序列化。

如何守护子进程

守护进程一般用于监控工作进程的运行状态,在工作进程不正常退出时重启工作进程,保障工作进程不间断运行。以下是一种实现方式。

/* daemon.js */
function spawn(mainModule) {
    var worker = child_process.spawn('node', [ mainModule ]);

    worker.on('exit', function (code) {
        if (code !== 0) {
            spawn(mainModule);
        }
    });
}

spawn('worker.js');
 

可以看到,工作进程非正常退出时,守护进程立即重启工作进程。

小结

本章介绍了使用NodeJS管理进程时需要的API以及主要的应用场景,总结起来有以下几点:

  • 使用process对象管理自身。

  • 使用child_process模块创建和管理子进程。

分享到:
评论

相关推荐

    Linux内核进程管理之进程ID.pdf

    5. 进程管理的API函数:文档中提到了一些内核API,如task_pid(), task_tgid(), task_pgrp()等,这些函数用于在内核代码中获取特定进程的PID,TGID或进程组ID。这些API函数对内核进行进程管理至关重要,它们简化了对...

    进程管理器,运行管理

    进程管理器是操作系统的核心组件,它负责管理和控制系统的执行单元——进程。在计算机科学中,进程是程序在执行时的一个实例,拥有独立的内存空间,包括代码、数据和栈。进程管理器则扮演着调度、创建、销毁以及监控...

    北邮-大三-操作系统-进程管理实验报告.doc

    5. Linux 系统中的进程管理:Linux 系统使用 sched.h 源码文件来管理进程。读取 sched.h 源码文件可以加深对进程管理概念的理解。 6. fork() 系统调用:fork() 系统调用是 Linux 系统中创建进程的方式。它可以创建...

    进程管理 操作系统作业

    5. 系统资源的使用和并发关系是非常重要的,通过进程管理,可以实现系统资源的合理分配和使用,提高系统的整体性能。 6. 通过任务管理器,可以查看进程的信息,包括进程的映像名称、PID、CPU使用率、内存使用情况等...

    实验一操作系统Windows“任务管理器”的进程管理.doc

    Windows 任务管理器的进程管理 Windows 任务管理器是 Windows 操作系统中的一种系统工具,提供了用户计算机上正在运行的程序和进程的相关信息。通过任务管理器,可以打开监视计算机性能的关键指示器,快速查看正在...

    完整版系统进程管理模块代码.rar

    系统进程管理是操作系统的核心组成部分,它负责控制、调度和协调计算机中的各个进程,确保系统资源的有效利用和程序的顺利执行。在"完整版系统进程管理模块代码.rar"这个压缩包中,我们很显然能获取到关于操作系统...

    Linux进程管理和网络管理.pdf

    5. 前后台进程管理 在shell中执行程序时,可以将程序放入后台执行。这通常通过在命令后加“&”来实现。同时,可以通过Ctrl+z将当前运行的前台进程挂起,使用jobs查看被挂起的进程。fg和bg命令分别可以将挂起的进程调...

    操作系统:进程管理-作业题目+答案

    操作系统中的进程管理是系统核心部分,它涉及到进程的创建、撤销、状态转换、调度和同步等关键概念。以下是对题目中涉及的知识点的详细解释: 1. 进程的特性: - 进程是动态的实体,包含了程序、数据和进程控制块...

    进程管理并取程序图标.rar

    在IT领域,进程管理和程序图标的获取是操作系统和软件开发中的关键部分。下面将详细解释这两个概念以及它们在实际操作中的应用。 首先,我们来理解什么是“进程管理”。在计算机科学中,进程是执行中的程序实例,每...

    基于Linux的进程管理分析.pdf

    5. Linux进程管理机制:Linux操作系统使用分时技术来实现多个进程的并发执行,每个进程都有自己的进程标识号,可以使用系统调用来创建新进程。 6. 父进程和子进程:在Linux操作系统中,第一个进程是手工建立的,...

    AIX操作系统(中文)\进程管理.pdf

    从给定的文件信息来看,文档主要聚焦于AIX操作系统中的进程管理,这是一个专业而复杂的主题,涉及到操作系统内部的工作机制以及如何有效地管理和控制在系统上运行的进程。下面,我们将详细解析并归纳出该文档中可能...

    进程管理 C 对于进程进行管理

    在计算机科学领域,进程管理是操作系统的核心组成部分,它涉及到如何创建、调度、同步和通信等对进程的操作。本文将深入探讨使用C语言进行进程管理的相关知识点。 首先,我们需要理解什么是进程。在操作系统中,...

    系统进程管理及源代码Code

    在计算机科学领域,系统进程管理是操作系统的核心组成部分,它负责创建、销毁、调度以及资源分配等与进程相关的操作。本文将深入探讨系统进程管理的概念、重要性及其源代码实现。 一、系统进程管理概述 系统进程是...

    操作系统进程管理

    5. Linux 系统下的进程管理:Linux 系统提供了丰富的进程管理接口,包括 fork、exec、wait 等。这些接口可以用来实现进程的创建、管理和同步。 6. semaphore:semaphore 是一种特殊的变量,用于表示系统资源的可用...

    操作系统进程管理实验报告(1).doc

    操作系统进程管理实验报告 操作系统进程管理实验报告(1)是一份关于进程管理的实验报告,涵盖了进程概念、进程创建、进程控制、进程互斥等方面的知识点。本文将对实验报告的内容进行详细的解释和分析。 1. 进程...

    易语言源码进程管理模块源码.rar

    接着,"进程管理.ec"文件应该是易语言的工程文件,包含了整个进程管理模块的所有源代码和相关设置。在易语言环境中打开此文件,可以直观地看到源码结构,包括各个函数、变量定义以及整体框架。EC(Engineering ...

    操作系统课程设计 实现段页式存储管理系统 实现1.创建进程 2.回收进程 3.回收段 4.显示段表 5.显示页表 6.展示内存 7.显示进程状态 0.离开

    在本课程设计中,我们将关注的是操作系统中的内存管理和进程管理,具体是段页式存储管理系统以及进程的生命周期管理。这里,我们用C++语言实现了这一系统,并在Linux环境下进行操作。 段页式存储管理系统是一种内存...

    操作系统模拟进程管理程序设计

    "操作系统模拟进程管理程序设计" 本资源主要讲述了操作系统中进程管理的模拟程序设计,通过模拟进程管理方法,了解进程的结构、进程的创建与撤销、进程的组织及进程的状态及其转换,掌握进程调度策略。下面是该资源...

    c 模拟进程管理.rar_操作系统 进程管理_模拟进程_进程管理_进程管理模拟_进程管理系统

    这个名为“c 模拟进程管理.rar”的压缩包提供了一个用C语言实现的模拟进程管理系统,适用于操作系统课程的教学和实践。 首先,我们要理解什么是进程。在计算机系统中,进程是程序的一次执行实例,包含了程序的代码...

    Linux进程管理实验.pdf

    Linux进程管理实验中涉及的核心知识点包括Linux操作系统中进程的概念、进程控制块(PCB)的结构、进程状态转换、fork()系统调用的工作原理以及相关内核函数。下面将详细解释这些概念和技术点。 Linux中的进程是一个...

Global site tag (gtag.js) - Google Analytics