背景
最近在做一个网上数据爬取的程序,涉及的数据量很大,大到几十万的级别。第一次遇到要处理这么大的数据量,心里还是有点懵圈的。毋庸置疑肯定是要用多进程了,一个程序跑到猴年马月也爬不完了。
pcntl_fork
官方解释在当前位置当前进程产生子分支。fork是创建了一个子进程,父进程和子进程 都从fork的位置开始向下继续执行,不同的是父进程执行过程中,得到的fork返回值为子进程号,而子进程得到的是0。
实例
实例1
$pid = pcntl_fork();
//父进程和子进程都会执行下面代码
if ($pid == -1) {
//错误处理:创建子进程失败时返回-1.
die('could not fork');
} else if ($pid) {
//父进程会得到子进程号,所以这里是父进程执行的逻辑
pcntl_wait($status); //等待子进程中断,防止子进程成为僵尸进程。
} else {
//子进程得到的$pid为0, 所以这里是子进程执行的逻辑。
}
从上面的代码可以看出,产生一个子进程只需要调用一下pcntl_fork
方法就可以了,失败时返回pid
为-1
,父进程pid
为1
,子进程pid
为0
。
那么如果产生多个子进程呢?
产生一个进程是调用一下pcntl_fork
,所以产生多个子进程就多次调用呗。
实例2
for ($i = 0; $i < 5; $i ++) {
$pid = pcntl_fork();
if (! $pid) {
sleep(1);
print "In child $i\n";
exit($i);
}
}
注意
:千万千万不要忘记在子进程里写exit
,否则会成指数式的产生子进程,服务器分分钟钟的搞死。
这样子就会产生5
个进程了,看着是不是很简单啊,那么坑爹地方来了~~~
我们爬取网上数据干什么用的?当然是存到数据库里自己用喽。那你肯定会想到这样子做了:
// 建立数据库连接
$conn = mysql_connect('127.0.0.1', 'root', 'root');
for ($i = 0; $i < 5; $i ++) {
$pid = pcntl_fork();
if (!$pid) {
// 抓取到的数据
$data = …………
// 存入数据库
$sql = "…………";
mysql_query($sql, $conn);
print "Ok! \n";
exit($i);
}
}
不好意思,MySQL server has gone away
,MySQL 不干了!!!
官方说法是这样子的:当子进程任务完成并结束的时候,会自己关闭数据库连接,下一进程再进行数据库操作的时候发现失去了数据库连接,因为就出现了MySQL server has gone away
的错误。详细说明 MySQL server has gone away错误
官方也给出了解决实例,But
是错的,我试了一下还是会现在上面的错误。已经无数次的折腾后,终于找到了解决的办法。
解决方法
for ($i = 0; $i < 5; $i ++) {
$pid = pcntl_fork();
// 建立数据库连接
$conn = mysql_connect('127.0.0.1', 'root', 'root', true);
if ($pid) {
// 建立新的数据库连接
$conn = mysql_connect('127.0.0.1', 'root', 'root', true);
} else if (! $pid) {
// 抓取到的数据
$data = …………
// 存入数据库
$sql = "…………";
mysql_query($sql, $conn);
print "Ok! \n";
exit($i);
}
}
只需注意两点:
- 建立数据库连接要在
fork
子进程之后 mysql_connect
连接时不要忘了在最后一参数上加true
以上就是快把我坑哭的经历,希望能帮助到一些人。因为在此过程中查阅了好多地方,竟然都是抄来官方例子说事,真心不知道他们有没有试过。
在此次大数据爬取过程中还遇到了好多好多的问题,烧死了无数的脑细胞,等有时间更新到下篇文章中,我先哭会~
fork操作完成后,子进程将拷贝父进程的文件描述符副本,指向同一个文件句柄(包含了当前文件读写的偏移量等信息)
也就是说,你的父子进程的mysql链接是同一个,所以会导致你这个问题,除此之外还会出现间歇性的响应body串掉问题
一般处理办法,需要保证你在子进程的链接是新的。或者别用多进程,php不需要
我最近也遇到了这个问题,欢迎交流:https://www.cnblogs.com/zhaoyixing/p/10847300.html
看了你写的博客写的挺好的,感觉PHP在多进程方面的处理确实不友好,容易有很多意向不到的问题出现