进程是资源分配的最小单位,线程是CPU调度的最小单位

1. 多线程并发:通过cURL并发请求

1.1 通过curl_multi实现

PHP cURL所有函数列表

并发中用的curl_multi_*相关函数

1.2 PHP curl_multi 实现并发请求步骤

  1. 调用 curl_multi_init,初始化一个批处理handle
  2. 循环调用 curl_multi_add_handle,往1中的批处理handle 添加curl_init来的子handle
  3. 持续调用 curl_multi_exec,直到所有子handle执行完毕。
  4. 根据需要循环调用 curl_multi_getcontent 获取结果
  5. 调用 curl_multi_remove_handle,并为每个字handle调用curl_close
  6. 调用 curl_multi_close

1.3 PHP curl_multi 实现代码

<?php

/**
* Functional description :
* Programmer : Mr.Liu
* @param array $urls
* $urls = [
'http://liuqinghui.dev.lywf.me/test/libin/ttt',
'http://liuqinghui.dev.lywf.me/test/libin/ttt',
'http://liuqinghui.dev.lywf.me/test/libin/ttt',
'http://liuqinghui.dev.lywf.me/test/libin/ttt',
'http://liuqinghui.dev.lywf.me/test/libin/ttt',
];
* @return array
*/
function multiGetRequest(array $urls):array
{

//1、初始化一个批处理handle
$mh = curl_multi_init();

//2、往批处理handle 添加curl_init来的子handle
foreach ($urls as $i => $url) {
$connect[$i] = curl_init($url);
curl_setopt($connect[$i], CURLOPT_HEADER, 0);
curl_setopt($connect[$i], CURLOPT_CONNECTTIMEOUT, 60);
curl_setopt($connect[$i], CURLOPT_RETURNTRANSFER, true);
curl_multi_add_handle($mh, $connect[$i]);
}

//3、并发执行,直到全部结束。
do {
curl_multi_exec($mh, $active);
} while ($active);

//4、获取结果
$return=[];
foreach ($urls as $i => $url) {
$return[] = curl_multi_getcontent($connect[$i]);

}
//5、移除子handle,并close子handle
foreach ($urls as $i => $url) {
curl_multi_remove_handle($mh, $connect[$i]);
curl_close($connect[$i]);
}

//6、关闭批处理handle
curl_multi_close($mh);
return $return;
}

2. 多进程并发:通过swoole_process实现

查看文档

2.1 示例代码

<?php

$start_time = microtime(true);
$urls = [
'http://liuqinghui.dev.lywf.me/test/libin/ttt',
'http://liuqinghui.dev.lywf.me/test/libin/ttt',
'http://liuqinghui.dev.lywf.me/test/libin/ttt',
'http://liuqinghui.dev.lywf.me/test/libin/ttt',
'http://liuqinghui.dev.lywf.me/test/libin/ttt',
];

//遍历任务创建子进程
foreach ($urls as $url) {
/**
* 创建子进程,并调用方法 my_process
*/
$process = new swoole_process("my_process", true);

/**
* 1.执行fork系统调用,启动进程;
* 创建成功返回子进程的PID,创建失败返回false
*/
$process->start();
/**
* 通过管道发数据到子进程。
* 管道是单向的:发出的数据必须由另一端读取。不能读取自己发出去的
*/
$process->write($url);

/**
* 保存进程,循环结算后统一调取返回数数据:
*/
$process_list[] = $process;

}
//读取结果
foreach ($process_list as $process){
//从管道中读取数据。
echo $rec = $process->read();
}

/**
* 子进程结束必须要执行wait进行回收,否则子进程会变成僵尸进程
* $ret 是个数组其数据结构:
array(3) {
'pid' =>
int(461)
'code' =>
int(0)
'signal' =>
int(0)
}
*/
while ($ret = swoole_process::wait()) {
$pid = $ret['pid'];
echo PHP_EOL . "Worker Exit, PID=" . $pid . PHP_EOL;
}


//子进程创建成功后要执行的函数
function my_process(swoole_process $worker)
{
sleep(1);//暂停1s
$url = $worker->read();
//---- 执行具体业务程序开始-----
$ch = curl_init();
// 设置URL和相应的选项
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
// 抓取URL并把它传递给浏览器
$return = curl_exec($ch);
// 关闭cURL资源,并且释放系统资源
curl_close($ch);
//---- 执行具体业务程序结束-----
$worker->write($return);//写入数据到管道
}
$end_time = microtime(true);
echo sprintf("use time:%.3f s\n", $end_time - $start_time);

3. 多进程和多线程的区别?如何选择

3.1 不同的维度的对比

对比维度 多进程 多线程 总结
数据共享、同步 数据共享复杂,需要用IPC;
数据是分开的,同步简单
因共享进程数据,数据共享简单。
但也因此导致同步复杂
各有优势
内存、CPU 占用内存多,切换复杂。
CPU利用率低
占用内存少,切换简单,CPU利用率高 线程占优
创建销毁、切换 创建销毁、切换复杂,速度慢 创建销毁、切换简单,速度很快 线程占优
编程、调试 编程简单,调试简单 编程复杂,调试复杂 进程占优
可靠性 进程间不会互相影响 一个线程挂掉将导致整个进程挂掉 进程占优
分布式 适应于多核、多机分布式;
扩展到多台机器比较简单
适应于多核分布式 进程占优

如何选择?