管道通訊可能會把腦袋弄壞。我想分享一些東西來避免這種結果。
為了正確控制透過已開啟子程序之「輸入」和「輸出」管道的通訊,請務必將兩者都設定為非阻塞模式,尤其要注意的是,`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";
?>