本文主要是介绍进程-线程-协程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
进程是什么?
计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配独立实体, 且每个进程拥有独立的地址空间,是操作系统结构的基础[最小的资源管理单元]
结论:进程是一个执行中的程序,需由上而下的一步步执行完成,既是基本的分配单元,也是基本的执行单元
线程是什么?
进程中的一个实体,只拥有运行时必不可少的资源,可与同一个进程下的所有线程共享资源[进程中的所有资源],别称:轻量级进程[程序执行流的最小单元|程序实际执行者]
结论:单个程序同时运行多个线程完成不同的工作,称为多线程
进程与线程的通俗理解:
示例1:
有一个老板想要开个工厂进行生产某件商品(例如剪子)
他需要花一些财力物力制作一条生产线,这个生产线上有很多的器件以及材料这些所有的 为了能够生产剪子而准备的资源称之为:进程。
只有生产线是不能够进行生产的,所以老板的找个工人来进行生产,这个工人能够利用这些材料最终一步步的将剪子做出来,这个来做事情的工人称之为:线程。
这个老板为了提高生产率,想到3种办法:
(1)在这条生产线上多招些工人,一起来做剪子,这样效率是成倍増长,即单进程 多线程方式
(2)老板发现这条生产线上的工人不是越多越好,因为一条生产线的资源以及材料毕竟有限,所以老板又花了些财力物力购置了另外一条生产线,然后再招些工人这样效率又再一步提高了,即多进程 多线程方式
(3)老板发现,现在已经有了很多条生产线,并且每条生产线上已经有很多工人了(即程序是多进程的,每个进程中又有多个线程),为了再次提高效率,老板想了个损招,规定:如果某个员工在上班时临时没事或者再等待某些条件(比如等待另一个工人生产完谋道工序 之后他才能再次工作) ,那么这个员工就利用这个时间去做其它的事情,那么也就是说:如果一个线程等待某些条件,可以充分利用这个时间去做其它事情,其实这就是:协程方式。
示例2:
进程:手机工厂车间[拥有资源]
线程:车间员工[实际执行人]
车间目的:生产成品[手机]
工厂车间中拥有着生产手机成品的所有资源。而车间员工都有着各自的工作岗位责任,负责某一块的业务,可以与人协助,生产出一部手机
图形理解:
代码示例:
多进程是依靠 pcntl_fork 来创建子进程,在启用多进程的时候需要进行模块检测
$processNumber = 5 ; #最大进程数if (function_exists('pcntl_fork')) {$pids = array();for ($x = 0; $x < $processNumber; $x++) {$pid = pcntl_fork();if ($pid == -1) {$this->log->writeLine("创建子进程失败!!\n");} elseif ($pid) {// 父进程. -- 一般不做任何处理echo '父进程最后执行'.PHP_EOL;$pids[] = $pid;} else {// 子进程.$this->run($this->processNumber);// 业务处理的地方echo '测试'.PHP_EOL;exit();}}// 等待子进程结束foreach ($pids as $pid) {pcntl_waitpid($pid, $status);}
} else {echo '当前PHP版本不支持pcntl_fork功能,运行失败'.PHP_EOL;exit();
}
PHP 本身是不支持多线程的,通过socket的方式来实现PHP多线程。
- 协程是什么?
一种轻量级的线程,只拥有寄存器上下文和栈,对栈操作,没有内核切换的开销,可以不加锁访问全局变量。
结论:原生的协程依靠yield和Generator[生成器]来实现。因没有内核切换开销,在IO瓶颈的时候可以很好的解决性能问题,可由用户在代码中控制,不陷入系统的控制
代码示例:
$result = $this->createRange(10); // 这里调用上面我们创建的函数
foreach($result as $value){sleep(1);echo $value.'<br />';
}function createRange($number){for($i=0;$i<$number;$i++){$data[] = time();}return $data;
}function createRange($number){for($i=0;$i<$number;$i++){yeild time();}
}
进程间的通信(IPC):
- 可通过消息队列进行通信,比如rabbitMQ,Kafka,Posix消息队列等,通过生产者和消费中的关系,进行数据交互
- 信号量,系统的一种原子性操作,同时只有一个进程能操作,当进程获取到某个信号量的时候,该进程就应该被释放掉。
sem_acquire 获取信号量
sem_release 释放信号量
- 共享内存,在系统中开辟一个公共的内存区域,任何进程同一时刻都可以访问该区域,为了确保数据一致性,需要对该区域进行加锁或者信号量
- 管道[posix_mkfifo],常用的进程间常用的通信手段,分为无名管道和有名管道,无名管道只能用于具有亲缘关系的进程间通信,而有名管道可以用于同一主机上任意进程
代码示例:
// 定义管道路径,与创建管道
$pipe_path = '/data/test.pipe';
if(!file_exists($pipe_path)){if(!posix_mkfifo($pipe_path,0664)){exit("create pipe error!");}
}
$pid = pcntl_fork();
if($pid == 0){ // 子进程,向管道写数据$file = fopen($pipe_path,'w');while (true){fwrite($file,'hello world');$rand = rand(1,3); sleep($rand);}exit('child end!');
}else{ // 父进程,从管道读数据$file = fopen($pipe_path,'r');while (true){$rel = fread($file,20);echo "{$rel}\n";$rand = rand(1,2);sleep($rand);}
}
总结:
1、在web应用中,我们每次访问php,就建立一个PHP进程,当然也会建立至少一个PHP线程。
2、PHP使用pcntl来进行多进程编程
3、PHP中使用pthreads来进行多线程编程
4、nginx的每个进程只有一个线程,每个线程可以处理多个客户端的访问
5、php-fpm使用多进程模型,每个进程只有一个线程,每个线程只能处理一个客户端访问。
6、apache可能使用多进程模型,也可能使用多线程模型,取决于使用哪种SAPI.
7、进程是cpu资源分配的最小单位,线程是cpu调度的最小单位
这篇关于进程-线程-协程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!