什么是进程
定义: 进程是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体
既然进程是系统进行资源分配和调度的基本单位, 那么在进程出现切换的时候必定会出现重新分配资源,进行上下文切换。 这样会导致cpu进行大量处理。
node 进程
node最让人莫名的就是单进程驱动了。这个单进程是指v8运行js代码的部分是单进程。单进程的好处是不必出现cpu经常切换。 但是因为这个特性导致多进程cpu无法并发处理。 而且, 只有一个核在跑, 其他的核在睡着, 并不能很好的利用好计算机。
怎样创建进程
在linux下,可以使用进程创建另外的进程, 既然可以自己创建, 那么肯定会有第一个爸爸级别的进程, 该结构可以使用pstree来查看, linux在开机的时候首先进入/etc/init里面,所以最上面的systemd应该是init的进程。
linux可以通过fork, exec*, 来创建进程。该函数在unistd.h库中。
下面是c创建fork()
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
pid_t pid = fork();
if( !pid ){
printf( "子进程id:%d\n" ,getpid() );
}else if( pid>0 ){
printf( "父进程id:%d,子进程ID:%d\n",getpid(),pid );
}else{
printf( "pass" );
exit(1);
}
return 1;
}
复制代码
fork(): 执行一次但有两个返回值. 在父进程中,返回值是子进程的进程号;在子进程中,返回值为0。因此可通过返回值来判断当前进程是父进程还是子进程。
使用fork函数得到的子进程是父进程的一个复制品,它从父进程处复制了整个进程的地址空间,包括进程上下文,进程堆栈,内存信息,打开的文件描述符,信 号控制设定,进程优 先级,。而子进程所独有的只是它的进程号器等。可以看出,使用 fork函数的代价是很大的,它复制了 父进程中的代码段,数据段和堆栈段里的大部分内容,使得fork函数的执行速度并不快。
c创建exec*()
首先, fork是一个复制品, 但是我们需要自己的进程, 这样可以使用exec* 函数实现。
#include <stdio.h>
#include <unistd.h>
int main()
{
execl("/bin/ls","ls","-l",NULL);
printf("如果execl执行失败, pass \n");
return 1;
}
复制代码
用exec函数可以把当前进程替换为一个新进程,且新进程与原进程有相同的PID。
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg, ..., char * const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
复制代码
path参数表示你要启动程序的名称包括路径名
arg参数表示启动程序所带的参数,一般第一个参数为要执行命令名,不是带路径且arg必须以NULL结束
返回值:成功返回0,失败返回-1
exce相当于覆盖了当前的进程, 那么怎样建立一个独立的进程且不影响原来的进程呢
fork() + exec*()
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
pid_t pid = fork();
switch( pid )
{
case 0:
execl("/bin/ls","ls","-l",NULL);
case -1:
exit(1);
default:
wait(NULL);
exit(0);
}
}
复制代码
wait(null) 让父进程等待子进程结束.
node 多进程架构
上面为什么要介绍c创建进程的方法, 因为node的本质是调用的cpp, 他创建进程的方法跟c一样像。 虽然node是单进程, 但是他提供child_process这个模块。
fork() 创建
创建master.js
var fork = require('child_process').fork;
for(var i = 0; i < 2; i++){
fork('./worker.js')
}
复制代码
创建worker.js
setInterval(function(){
console.log(Math.random())
},200)
复制代码
然后运行master.js 这时候两个进程都会工作。 可以使用
ps aux | grep worker.js
复制代码
命令查看有几个进程在运行。 因为我们用node执行的mastes.js文件, 而创建时用的fork创建的, 所以worker.js也用node执行。
spawn() 启动子进程来执行命令
exec() 启用子进程来执行命令, 但是他有回调
execFile(): 启用子进程来执行可执行文件
注意后面三个的区别, 前两个是命令, 最后一个是可执行文件 也就是说在调用的时候要这么写
fork.exec('node worker.js', function(){//node worker.js 是在command line 中执行js文件
});
fork.execFile('worker.js',function(){//worker.js 需要时可执行文件
})
复制代码
node文件变成可执行文件可以再第一行添加
#!/usr/local/bin/node
复制代码