代码:
// 一个数据库连接
// 供应近百个进程并行使用
// 结果导致,只有第一个创建的进程插入了数据
// 后面的进程全部无法插入数据到数据库
// 提示 MySQL server has gone away
$con = new PDO('mysql:host=127.0.0.1;dbname=Process' , 'root' , '364793');
$num = 50 * 10000; // 插入的数量
$tb_name = 'test_tb';
$sex_range = array("男" , "女" , "两性" , "未知" , "male" , "female" , "both" , "unknow");
$sex_range_count = count($sex_range);
$unit_num = 5000; // 单次插入数量
$p_list = array();
$p_num = ceil($num / $unit_num);
$is_main_process = true;
$file = '/home/cxl/桌面/insert.log';
// 清空插入日志(以便重新计算插入耗费时间)
$fs = fopen($file , 'w');
fwrite($fs , '');
fclose($fs);
for ($n = 1; $n <= $p_num; ++$n)
{
$min = ($n - 1) * $unit_num;
$max = min($min + $unit_num , $num);
// echo 'per insert number: min->' . $min . ' ; max->' . $max . PHP_EOL;
$p = pcntl_fork();
if ($p === -1) {
exit('create process ' . $n . ' failed!' . PHP_EOL);
} else if ($p === 0) {
$is_main_process = false;
$sql = 'insert into ' . $tb_name . ' (name , sex , height) values ';
for ($i = $min; $i < $max; ++$i)
{
// name
$name = join('' , random(10 , 'mixed'));
// sex
shuffle($sex_range);
$sex = $sex_range[rand(0 , $sex_range_count - 1)];
// height
$height = rand(50 , 175);
$sql .= '("' . $name . '" , "' . $sex . '" , ' . $height . ') ,';
}
$sql = mb_substr($sql , 0 , -1);
// 每批次插入开始时间
$s_time = microtime(true);
if (!$con->query($sql)) {
exit('插入批次:' . $n . ' 失败' . PHP_EOL);
}
// 每批次插入结束时间
$e_time = microtime(true);
// 每批次插入耗费的时间
$duration = $e_time - $s_time;
// 输出信息
echo '插入批次 ' . $n . ' 花费时间: ' . $duration . 's' . PHP_EOL;
// 记录每次插入耗时(用于统计总耗时)
$fs = fopen($file , 'a');
fwrite($fs , $duration . "\r\n");
fclose($fs);
break;
} else {
$p_list[] = $p;
}
}
结果:
貌似是子进程1结束的时候,所有的资源都释放了,而其中的pdo对象时复制的父进程的,文件描述符是同一个,然后也就被关闭了,其它进程执行的时候自然就会出现mysql连接断开了。
另外,不要多个进程共用一个mysql连接,如果共用1个连接,那么返回的结果无法保证被哪个进程处理。持有连接的进程理论上都可以对这个连接进行读写,这样数据就发生错乱了。
参考:是否可以共用1个redis或mysql连接,对pcntl同样有效