管道通信可能会让人崩溃,我想分享一些东西来避免这种情况。
为了正确控制通过打开的子进程的“in”和“out”管道进行的通信,请记住将它们都设置为非阻塞模式,并且尤其注意 fwrite 可能返回 (int)0,但这并不意味着错误,只是进程可能在那一刻没有接受输入。
因此,让我们考虑一个使用 funzip 作为子进程来解码 gz 编码文件的示例:(这不是最终版本,只是为了展示重要的事情)
<?php
$fd=fopen("/tmp/testPipe", "w");
for($i=0;$i<100000;$i++)
fwrite($fd, md5($i)."\n");
fclose($fd);
if(is_file("/tmp/testPipe.gz"))
unlink("/tmp/testPipe.gz");
system("gzip /tmp/testPipe");
$pipesDescr=array(
0 => array("pipe", "r"),
1 => array("pipe", "w"),
2 => array("file", "/tmp/testPipe.log", "a"),
);
$process=proc_open("zcat", $pipesDescr, $pipes);
if(!is_resource($process)) throw new Exception("popen error");
stream_set_blocking($pipes[0], 0);
stream_set_blocking($pipes[1], 0);
$text="";
$fd=fopen("/tmp/testPipe.gz", "r");
while(!feof($fd))
{
$str=fread($fd, 16384*4);
$try=3;
while($str)
{
$len=fwrite($pipes[0], $str);
while($s=fread($pipes[1], 16384*4))
$text.=$s;
if(!$len)
{
usleep(200000);
$try--;
if(!$try)
throw new Exception("fwrite error");
}
$str=substr($str, $len);
}
echo strlen($text)."\n";
}
fclose($fd);
fclose($pipes[0]);
stream_set_blocking($pipes[1], 1);
while(!feof($pipes[1]))
{
$s=fread($pipes[1], 16384);
$text.=$s;
}
echo strlen($text)." / 3 300 000\n";
?>