说的都是只兼容unix 服务器的多进程,下面来讲讲在window 和 unix 都兼容的多进程(这里是泛指,下面的curl实际上是通过IO复用实现的)。

通过扩展实现多线程的典型例子是CURL,CURL 支持多线程的抓取网页的功能。

这部分过于抽象,所以,我先给出一个CURL并行抓取多个网页内容的一个分装类。这个类实际上很实用,

详细分析这些函数的内部实现将在下一个教程里面描述。

你可能不能很好的理解这个类,而且,php curl 官方主页上都有很多错误的例子,在讲述了其内部机制

后,你就能够明白了。

先看代码:

classHttp_MultiRequest

{//要并行抓取的url 列表

private $urls =array();//curl 的选项

private$options;//构造函数

function __construct($options =array())

{

$this->setOptions($options);

}//设置url 列表

function setUrls($urls)

{

$this->urls =$urls;return $this;

}//设置选项

function setOptions($options)

{

$options[CURLOPT_RETURNTRANSFER]= 1;if (isset($options[‘HTTP_POST‘]))

{

curl_setopt($ch, CURLOPT_POST,1);

curl_setopt($ch, CURLOPT_POSTFIELDS, $options[‘HTTP_POST‘]);

unset($options[‘HTTP_POST‘]);

}if (!isset($options[CURLOPT_USERAGENT]))

{

$options[CURLOPT_USERAGENT]= ‘Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1;)‘;

}if (!isset($options[CURLOPT_FOLLOWLOCATION]))

{

$options[CURLOPT_FOLLOWLOCATION]= 1;

}if (!isset($options[CURLOPT_HEADER]))

{

$options[CURLOPT_HEADER]= 0;

}

$this->options =$options;

}//并行抓取所有的内容

function exec()

{if(empty($this->urls) || !is_array($this->urls))

{return false;

}

$curl= $data =array();

$mh=curl_multi_init();foreach($this->urls as $k =>$v)

{

$curl[$k]= $this->addHandle($mh, $v);

}

$this->execMulitHandle($mh);foreach($this->urls as $k =>$v)

{

$data[$k]=curl_multi_getcontent($curl[$k]);

curl_multi_remove_handle($mh, $curl[$k]);

}

curl_multi_close($mh);return$data;

}//只抓取一个网页的内容。

function execOne($url)

{if(empty($url)) {return false;

}

$ch=curl_init($url);

$this->setOneOption($ch);

$content=curl_exec($ch);

curl_close($ch);return$content;

}//内部函数,设置某个handle 的选项

privatefunction setOneOption($ch)

{

curl_setopt_array($ch, $this->options);

}//添加一个新的并行抓取 handle

privatefunction addHandle($mh, $url)

{

$ch=curl_init($url);

$this->setOneOption($ch);

curl_multi_add_handle($mh, $ch);return$ch;

}//并行执行(这样的写法是一个常见的错误,我这里还是采用这样的写法,这个写法//下载一个小文件都可能导致cup占用100%, 并且,这个循环会运行10万次以上//这是一个典型的不懂原理产生的错误。这个错误在PHP官方的文档上都相当的常见。)

privatefunction execMulitHandle2($mh)

{

$i= 0;

$running= null;do{

curl_multi_exec($mh, $running);

$i++;

}while ($running > 0);//var_dump($i);

}//应该用这样的写法

privatefunction execMulitHandle($mh)

{

$i= 0;do {$mrc = curl_multi_exec($mh,$active); $i++;} while ($mrc ==CURLM_CALL_MULTI_PERFORM);while ($active && $mrc ==CURLM_OK)

{if (curl_multi_select($mh) != -1)

{do {$mrc = curl_multi_exec($mh, $active); $i++;} while ($mrc ==CURLM_CALL_MULTI_PERFORM);

}

$i++;

}//var_dump($i);

}

}

看最后一个注释最多的函数,这个错误在平时调试的时候可能不太容易发现,因为程序完全正常,但是,在生产服务器下,马上会引起崩溃效果。

解释为什么不能这样,必须从C 语言内部实现的角度来分析。这个部分将放到下一个教程(PHP高级编程之–单线程实现并行抓取网页 )。不过不是通过C语言来表述原理,而是通过PHP

这个类,实际上也就很简单的实现了前面我们费了4个教程的篇幅,并且是九牛二虎之力才实现的多线程的抓取网页的功能。在纯PHP的实现下,我们只能用一个后台服务的方式来比较好的实现,但是当你使用 操作系统接口语言 C 语言时候,这个实现当然就更加的简单,灵活,高效。

就同时抓取几个网页这样一件简单的事情,实际上在底层涉及到了很多东西,对很多半路出家的PHP程序员,可能不喜欢谈多线程这个东西,深入了就涉及到操作系统,浅点说就是并行运行好几个“程序”。但是,很多时候,多线程必不可少,比如要写个快点的爬虫,往往就会浪费九牛二虎之力。不过,PHP的程序员现在应该感谢CURL 这个扩展,这样,你完全不需要用你不太精通的 python 去写爬虫了,对于一个中型大小的爬虫,有这个内部多线程,就已经足够了。

最后是上面的类的一个测试的例子:

$urls = array("http://baidu.com", "http://baidu.com", "http://baidu.com", "http://baidu.com", "http://baidu.com", "http://baidu.com", "http://www.google.com", "http://www.sina.com.cn", );

$m= newHttp_MultiRequest();

$t= microtime(true);

$m->setUrls($urls);//parallel fetch(并行抓取):

$data = $m->exec();

$parallel_time= microtime(true) -$t;

echo $parallel_time ."\n";

$t= microtime(true);//serial fetch(串行抓取):

foreach ($urls as$url)

{

$data[]= $m->execOne($url);

}

$serial_time= microtime(true) -$t;

echo $serial_time ."\n";

原文:http://www.cnblogs.com/chunguang/p/5578464.html

PHP是4个进程还是五个,PHP多进程(4) :内部多进程相关推荐

  1. 进程的五种基本状态VS活动就绪静止就绪活动阻塞静止阻塞

    进程的五种基本状态 1 创建状态: 进程正在被创建 2 就绪状态: 进程被加入到就绪队列中等待CPU调度 3 执行状态: 进程正在被运行 4 等待阻塞状态: 进程因为某种原因,比如等待I/O,等待设备 ...

  2. 父进程创建五个子进程

    父进程创建五个子进程 #include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<sys ...

  3. 什么是进程,什么是线程,多线程与多进程的区别?

    什么是进程,什么是线程,以及什么实际场景使用他们? 进程(Process):是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础.简言之运行的程序就 ...

  4. linux 进程 控制终端,linux系统编程之进程(五):终端、作业控制与守护进程

    #include#define ERR_EXIT(m) do { perror(m); exit(EXIT_FAILURE); } while(0) int setup_daemon(int, int ...

  5. 操作系统中进程的五种状态与JAVA中线程的六种状态

    操作系统中的五种状态 新建:创建新的进程 就绪:进程已经获得除CPU时间片以外的任何资源,一旦获得cpu时间片就能立马执行. 执行:处于就绪队列中的进程获得了时间片运行进程. 阻塞:进程时间片用完进入 ...

  6. linux杀死进程的五种方法

    方法一: Terminal终端输入: gnome-system-monitor,就可以打开system monitor 如图: 然后找到相应进程,右击选择kill process就可以了 方法二: 通 ...

  7. linux进程的五种状态

    Linux将进程状态描述为如下五种: 1.TASK_RUNNING:可运行状态,处于该状态的进程可以被调度执行而成为当前进程. 2.TASK_INTERRUPTIBLE:可中断睡眠状态,处于该状态的进 ...

  8. linux进程--僵尸进程(五)

    1.基本概念 我们知道在unix/linux中,正常情况下,子进程是通过父进程创建的,子进程在创建新的进程.子进程的结束和父进程的运行是一个异步过程,即父进程永远无法预测子进程 到底什么时候结束. 当 ...

  9. 进程的五种状态和线程的六种状态

    参考文章: 进程的状态转换和线程的状态转换

  10. 进程的五种基本状态 - 操作系统

    创建状态:进程在创建时需要申请一个空白PCB,向其中填写控制和管理进程的信息,完成资源分配.如果创建工作无法完成,比如资源无法满足,就无法被调度运行,把此时进程所处状态称为创建状态 就绪状态:进程已经 ...

最新文章

  1. android查找邮件程序,Android 程序崩溃日志邮件获取
  2. cpu子系统(优化)
  3. explain mysql 调优_explain mysql性能优化
  4. 两层或以上的showModalDialog解决方法
  5. 配置kubernetes服务basic auth
  6. Spring boot定制错误json数据
  7. qt5.10 for android 使用webview时qml 与html 中js的相互访问
  8. string最大容量_string初步使用
  9. 高质量响应式的 HTML/CSS 网站模板
  10. MooseFS源代码分析(三)
  11. 最清晰的VGG16模型图
  12. ffmpeg命令下载m3u8原画质视频
  13. Latex overleaf 图表公式参考文献
  14. c语言 写播放器,C语言实现Mini-Cooledit音频播放器(13页)-原创力文档
  15. 360html收藏夹,360浏览器的收藏夹如何保存?360浏览器收藏夹备份方法
  16. Android Fragmnet-Fragment数据交换以及ListFragment的使用
  17. python整数和浮点数
  18. BLE Error Codes 查表
  19. 企业架构概述及业务架构详解
  20. .net 程序访问数据库之异常SqlException (0x80131904)

热门文章

  1. python找最长的字符串_Python简单实现查找一个字符串中最长不重复子串的方法
  2. python编写arcgis脚本_ArcGis Python脚本——批量添加字段
  3. Ⅴ0还有别的方法设置图案吗_水冷空调扇如何使用 水冷空调扇使用方法介绍【图文】...
  4. 20190703 日子
  5. 常见的四种文本自动分词详解及IK Analyze的代码实现
  6. Jmeter中的变量(三)
  7. css简单的数学运算
  8. FreeRTOS的内存管理
  9. Set Matrix Zeros
  10. Jaxb2 转换XML文档