我的脚本检查HTTP服务器是否正在响应...它应该每隔60秒询问列表中的所有服务器。但它根本不会等待。知道为什么吗?它确实执行睡眠线(就像我在那里做回声一样,确实出现了),但是在那60秒内没有停止......只有在达到子限制时才会停止(在这种情况下 - 从不)。知道为什么吗?
PHP 5.4.41-0 + deb7u1
<?php
echo "[".date("Y-m-d H:i:s")."] Starting...\n";
declare(ticks = 1); // cpu directive
error_reporting(0); // screw warnings
set_time_limit(0); // no limits!
$ctx = stream_context_create(array( // timeout file_get_contents context
'http' => array(
'timeout' => 30 // half of time between requests
)
)
);
$test_urls = array( // test urls
'URL1' => 'http://www.google.com',
'URL2' => 'http://www.ebay.de'
);
$max=10;
$child=0;
$rec_id=0;
function sig_handler($signo) {
global $child;
switch ($signo) {
case SIGCHLD:
$child -= 1;
}
}
pcntl_signal(SIGCHLD, "sig_handler"); // register fork signal handler to count running children
$loop = 0;
while (true){ // <main_loop>
$loop++;
foreach($test_urls as $uid => $url){ // <test_urls>
echo "[".date("Y-m-d H:i:s")."] ENTERING LOOP:$loop\n";
while ($child >= $max) {
sleep(1);
}
$child++;
$rec_id++;
if($rec_id > 999999) $rec_id = 1; // limit rec_id, so it wouldn't cause an out of bounds error
$pid=pcntl_fork();
if($pid){
// If you're here, something is totally messed up.
}else{ // <fork>
$req_start = microtime(true);
$result = file_get_contents($url,NULL,$ctx);
$req_time = microtime(true) - $req_start;
if($result) echo "[".date("Y-m-d H:i:s")."] OK - $req_time\n";
else echo "[".date("Y-m-d H:i:s")."] ERROR - $req_time\n";
sleep(1); // avoid segmentation fault, when fork ends before handling signals
exit;
} // </fork>
} // </test_urls>
echo "[".date("Y-m-d H:i:s")."] GOING TO SLEEP ON LOOP: $loop\n";
sleep(60); // test every 60 seconds (if childs are available!)
echo "[".date("Y-m-d H:i:s")."] WAKING UP LOOP: $loop\n";
} // </main_loop>
while($child != 0){
sleep(1);
}
?>
结果:*
[2015-08-05 18:17:43] Starting...
[2015-08-05 18:17:43] ENTERING LOOP:1
[2015-08-05 18:17:43] ENTERING LOOP:1
[2015-08-05 18:17:43] GOING TO SLEEP ON LOOP: 1
[2015-08-05 18:17:43] OK - 0.36189103126526
[2015-08-05 18:17:44] OK - 0.99003601074219
[2015-08-05 18:17:44] WAKING UP LOOP: 1
[2015-08-05 18:17:44] ENTERING LOOP:2
[2015-08-05 18:17:44] ENTERING LOOP:2
[2015-08-05 18:17:44] GOING TO SLEEP ON LOOP: 2
[2015-08-05 18:17:44] OK - 0.30263018608093
[2015-08-05 18:17:45] WAKING UP LOOP: 2
[2015-08-05 18:17:45] ENTERING LOOP:3
[2015-08-05 18:17:45] ENTERING LOOP:3
[2015-08-05 18:17:45] GOING TO SLEEP ON LOOP: 3
[2015-08-05 18:17:45] OK - 0.445955991745
[2015-08-05 18:17:45] OK - 1.2020018100739
[2015-08-05 18:17:45] WAKING UP LOOP: 3
[2015-08-05 18:17:45] ENTERING LOOP:4
[2015-08-05 18:17:45] ENTERING LOOP:4
[2015-08-05 18:17:45] GOING TO SLEEP ON LOOP: 4
[2015-08-05 18:17:46] OK - 1.0700960159302
[2015-08-05 18:17:46] OK - 0.5119640827179
[2015-08-05 18:17:46] WAKING UP LOOP: 4
[2015-08-05 18:17:46] ENTERING LOOP:5
[2015-08-05 18:17:46] ENTERING LOOP:5
[2015-08-05 18:17:46] GOING TO SLEEP ON LOOP: 5
[2015-08-05 18:17:46] WAKING UP LOOP: 5
[2015-08-05 18:17:46] ENTERING LOOP:6
[2015-08-05 18:17:46] ENTERING LOOP:6
[2015-08-05 18:17:46] GOING TO SLEEP ON LOOP: 6
[2015-08-05 18:17:47] OK - 0.43205118179321
[2015-08-05 18:17:47] WAKING UP LOOP: 6
[2015-08-05 18:17:47] ENTERING LOOP:7
[2015-08-05 18:17:47] ENTERING LOOP:7
[2015-08-05 18:17:47] OK - 1.3988509178162
[2015-08-05 18:17:47] GOING TO SLEEP ON LOOP: 7
[2015-08-05 18:17:47] OK - 0.59426283836365
[2015-08-05 18:17:47] WAKING UP LOOP: 7
[2015-08-05 18:17:47] ENTERING LOOP:8
[2015-08-05 18:17:47] ENTERING LOOP:8
[2015-08-05 18:17:47] GOING TO SLEEP ON LOOP: 8
[2015-08-05 18:17:47] OK - 1.2100639343262
[2015-08-05 18:17:47] OK - 0.5920991897583
答案 0 :(得分:3)
sleep
可以被信号中断,在这种情况下,它将返回剩余的秒数并且不会继续。它可能收到的一个信号是孩子在执行期间被杀死(SIGCHLD
)。您可以检查sleep
的返回值,以确定是否有信号中断它,但我猜它确实退出SIGCHLD
。
在linux机器上返回值will be the remaining seconds to sleep,这样你就可以将睡眠置于循环中并休眠直到剩余的秒数为0,或者是否存在其他类型的错误(由{{发出信号) 1}}回复)
这样的事情可能有用:
FALSE
另请注意,在您的原始代码中,您有一条评论说明:
$timeLeft = 60;
while ($timeLeft > 0) {
$timeLeft = sleep($timeLeft);
}
实际上是fork完成后的父部分,因此每次都会实际执行分支。您可能想要更改此评论,因为它可能会让您或任何其他阅读代码的人感到困惑,或者只是通过// If you're here, something is totally f***ed up. *<-- Edited for family friendliness*
检查来完全删除