进程与线程的简单解释

计算机的核心是 CPU ,它承担了所有的计算任务,就像一座工厂,时刻在运行

 

 

假定工厂的电力有限,一次只能供给一个车间的使用。

也就是说,一个车间开工的时候,其他车间必须停工。

背后的含义就是,单核 CPU 一次只能运行一个任务。

 

 

进程就好比工厂的车间,它代表 CPU 所能处理的单个任务,任意时刻, CPU 总是运行一个进程,其他进程处于非运行状态。

 

 

一个车间里,可以有很多工人,他们协同完成一个任务。

 

 

线程就好比车间里的工人,一个进程可以包括多个线程。

 

 

车间的空间是工人们共享的,比如许多房间是每个工人都可以进出的,这象征一个进程的内存空间是共享的,每个线程都可以使用这些共享内存。

 

 

可是,每个房间的大小不同,有些房间最多只能容纳一个人,比如厕所,里面有人的时候,其他人就不能进去了,这代表一个线程使用某些共享内存时,其他线程必须等它结束,才能使用这一块内存。

 

 

一个防止他人进入的简单方法,就是门口加一把锁,先到的人锁上门,后到的人看到上锁,就在门口排队,等锁打开再进去。这就叫 「互斥锁」 防止多个线程同时读写某一块内存区域。

 

 

还有一些房间,可以同时容纳 N 个人,比如厨房,也就是说,如果人数大于 N  多出来的人只能在外面等着。这好比某些内存区域,只能供给给固定数目的线程使用。

 

 

这时的解决方法,就是在门口挂 N 把钥匙。进取的人就取一把钥匙,出来时再把钥匙挂回原处,后到的人发现钥匙架空了,就知道必须在门口排队等着了,这种做法叫做 「信号量」用来保证多个线程不会互相冲突

 

不难看出 「互斥锁」 「信号量」 的一种特殊情况(N=1时),也就是说,完全可以用后者代替前者,但是因为 「互斥锁」 较为简单,且效率高,所以在必须保证资源独占的情况下,还是采用这种设计

 

 

操作系统的设计,因此可以归纳为三点:

①以多进程形式,允许多个任务同时运行。

②以多线程形式,允许但是任务分成不同的部分运行。

③提供协调机制,一方面防止进程之间和线程之间产生冲突,另一方面允许进程之间和线程之间共享资源。

 

以上内容来自  进程与线程的一个简单解释

 

进程、线程间的关系

比如打开一个 Word 这个任务就是打开了一个进程,但是在 Word 操作的时候可以同时进行打字,拼写检查等操作,像这样,在一个进程内部,同时运行着多个 「子任务」。

从上面的例子可以知道进程是由多个线程组成的,一个进程至少要有一个线程,实际上,线程是操作系统中最小的执行单元。

 

进程、线程的区别

 

进程

进程之间不共享任何状态

进程的调度由操作系统完成

每个进程都有自己独立的内存空间

进场间通讯主要是通过信号传递的方式来实现的,实现方式有多种,信号量,管道,事件等,任何一种方式的通讯效率都需要过内核,导致通讯效率比较低

由于是独立的内存空间,上下文切换的时候需要保存先调用栈的信息,CPU 各寄存器的信息,虚拟内存,以及打开的相关句柄等信息,所以导致上下文进程间切换开销很大,通讯很麻烦

 

线程

线程之间共享变量,解决了通讯麻烦的问题对于变量的访问需要锁

一个进程可以拥有多个线程,但是其中每个线程会共享父进程向系统申请资源,这个包括虚拟内存,文件等。由于是共享资源,所有创建线程所需要的系统资源占用比进程小很多,相应的可创建的线程数量也变得相对多很多

另外在调度方面也是由于内存是共享的,所以上下文切换的时候需要保存的东西就相对少一些,这样一来上下文的切换也变的高效。

 

进程的基本知识


所谓进程其实就是操作系统中一个正在运行的程序,在一个终端当中,通过 php  运行一个 php 文件,这个时候就相当于创建了一个进程,这个进程会在系统中贮存,申请属于它自己的内存空间,系统资源并且运行相应的程序

 

对于一个进程来说,它的核心内容分为两部分

 

一个是它的内存,这个内存是这进程创建之初从系统分配的,它所有创建的变量都会储存在这一片内存环境当中;

另一个是它的上下文环境,我们知道进程是运行在操作系统的,那么对于程序来说,它的运行依赖操作系统分配给它的资源,操作系统的一些状态。


在操作系统中可以运行多个进程的,对于一个进程来说,他可以创建自己的子进程,当我们在一个进程创建出若干个子进程的时候,子进程和父进程一样,拥有自己的内存空间和上下文环境:

 

如图:

 

 

Swoole 的进程结构


Swoole 的高效不仅仅于底层使用 C 编写,它的进程结构模型也使其可以高效的处理业务;

进程结构图:

 

 

Swoole 这几个进程的作用:

 

Master 进程:主进程

 

第一层:master 进程,这个是 swoole 的主进程,这个进程是用于处理 swoole 的核心事件驱动的,在这个进程当中可以看到它拥有一个 MainReactor 以及若干个 Reactor , swoole 所有对于事件的监听都会在这些线程中实现,比如客户端的连接,信号处理等

 

 

每一个线程都有自己的用途,以下是对每个线程的解释:

 

MainReactor 「主线程」

 

主线程会负责监听 server socket ,如果有新的连接 accept ,主线程会评估每个 Reactor 线程的连接数量,将此连接分配给连接数最少的 Reactor 线程,做一个负载均衡

 

Reactor 线程组

 

Reactor 线程组负责维护客户端机器的 TCP 连接、处理网络 IO、收发数据完全是异步非阻塞的模式

 

swoole 的主线程在 accpet 新的连接后,会将这个连接分配给一个固定的 Reactor 线程,在 socket 可读时读取数据,并进行协议解析,将请求投递到 worker 进程,在 socket 可写时将数据发送给 TCP客户端

 

心跳包检测线程 HeartbeatCheck」

 

swoole 配置了心跳检测之后,心跳包线程会在固定的时间内对所有之前在线的连接发送检测数据包

 

UDP 收包线程 「UdpRecv」

 

接受并处理客户端 UDP 数据包

 

Manager 进程:管理进程

 

swoole 想要实现最好的性能必须创建出多个工作进程帮助处理任务,但 worker 进程就必须 fork 操作,但是 fork 操作是不安全的,如果没有管理会出现很多的僵尸进程,进而影响服务器性能,同时 worker 进程被误杀或者由于程序的原因会异常退出,为了保证服务的稳定性,需要重新创建 worker 进程

 

swoole 在运行中会创建一个单独的管理进程,所有的 worker 进程和 task 进程都是从管理进程 fork 出来的,管理进程会监视所有子进程的退出事件,当 worker 进程发生致命错误或者运行生命周期结束时,管理进程会回收此进程,并创建新的进程。换句话说,对于 worker,task 进程的创建,回收等操作全权由 「保姆」 Manager 进程进行管理

 

Manager 进程和 worker/task 进程的关系

 

 

Worker 进程:工作进程

 

worker 进程属于 swoole 的主逻辑进程,用户处理客户端的一系统请求,接受由 Reactor 线程投递的请求数据包,并执行 PHP 回调函数处理数据生成响应数据并发给 Reactor 线程,由 Reactor 线程发送给 TCP 客户端可以是异步非阻塞模式,也可以是同步阻塞模式

 

Task 进程:异步任务工作进程

 

taskWorker 这一进程是 swoole 提供的异步工作进程,这些进程主要用于处理一些耗时较长的同步任务,在 worker 进程中投递过来