使用cron运行Foreach循环的PHP脚本-花费的时间太长-如何更快地完成
我正在尝试用PHP创建一个网站监控webapp。要监视的网站的URL存储在MySQL表中。脚本通过cron每分钟运行一次——它在所有网站和foreach URL中循环,它使用CURL访问网站,使用CURLINFO_HTTP_代码获取HTTP代码——如果网站正常运行,则返回true,否则返回false 脚本运行正常-一两个网站的运行时间为毫秒,而20个网站的运行时间平均为2-15秒。我可以看到,当添加更多的站点时,这将导致问题——理想情况下,我需要监控数千个站点,用户能够添加自己的站点 我曾经考虑过,当用户添加一个要监视的站点时,会为每个URL添加单独的cron和文件,但是我不确定该如何进行,而且我可以预见在共享服务器上工作时会出现一些问题 那么我该怎么做呢,还是有更好的方法我还没有想到呢使用cron运行Foreach循环的PHP脚本-花费的时间太长-如何更快地完成,php,performance,cron,Php,Performance,Cron,我正在尝试用PHP创建一个网站监控webapp。要监视的网站的URL存储在MySQL表中。脚本通过cron每分钟运行一次——它在所有网站和foreach URL中循环,它使用CURL访问网站,使用CURLINFO_HTTP_代码获取HTTP代码——如果网站正常运行,则返回true,否则返回false 脚本运行正常-一两个网站的运行时间为毫秒,而20个网站的运行时间平均为2-15秒。我可以看到,当添加更多的站点时,这将导致问题——理想情况下,我需要监控数千个站点,用户能够添加自己的站点 我曾经考虑
<?php
function visit($url) {
// VISITS WEBSITE - RETURNS TRUE IF SITE UP, FALSE IF DOWN
}
// GETS THE MONITOR DETAILS FROM DATABASE
$monitor = new Table($monitorInstance);
$all_monitors = $monitor->get('monitors');
$monitors = $monitor->tableData();
//LOOP THROUGH ALL MONITORS
foreach ($monitors as $monitor1) {
$id = $monitor1->id; //GETS ID
$website = $monitor1->url; //GETS URL
$status = $monitor1->status; //GETS STATUS - 'up' or 'down'
// RUNS FUNCTION
if (visit($website)) {
$new_status = 'up';
} else {
$new_status = 'down';
}
// IF STATUS CHANGE UPDATE THE DATABASE
if ($new_status != $status) {
try {
//update the database with the new status
$monitor->update('monitors', $id, array(
'status' => $new_status,
));
} catch(Exception $e) { //catch exceptions
die($e->getMessage());
}
// ALSO SEND EMAIL TO USER
}
}
并行运行请求
PHP在并行任务方面通常不是很好,但它确实是可能的。简言之,HTTP请求是一项非常缓慢的任务——在您的服务器和远程服务器之间有很多来回。PHP通常是按顺序设计的——这意味着它一次只做一件事。因此,只需等待远程服务器一次一个地响应,就会浪费大量时间
- 发出一个请求
- 久等
- 发出一个请求
- 久等
- 等等李>
相反,您要做的是确保一起发送大量请求,然后同时等待它们。幸运的是,PHP提供了这样的功能
以下是关于主题的函数示例:
<?php
function multiRequest($data, $options = array()) {
// array of curl handles
$curly = array();
// data to be returned
$result = array();
// multi handle
$mh = curl_multi_init();
// loop through $data and create curl handles
// then add them to the multi-handle
foreach ($data as $id => $d) {
$curly[$id] = curl_init();
$url = (is_array($d) && !empty($d['url'])) ? $d['url'] : $d;
curl_setopt($curly[$id], CURLOPT_URL, $url);
curl_setopt($curly[$id], CURLOPT_HEADER, 0);
curl_setopt($curly[$id], CURLOPT_RETURNTRANSFER, 1);
// post?
if (is_array($d)) {
if (!empty($d['post'])) {
curl_setopt($curly[$id], CURLOPT_POST, 1);
curl_setopt($curly[$id], CURLOPT_POSTFIELDS, $d['post']);
}
}
// extra options?
if (!empty($options)) {
curl_setopt_array($curly[$id], $options);
}
curl_multi_add_handle($mh, $curly[$id]);
}
// execute the handles
$running = null;
do {
curl_multi_exec($mh, $running);
} while($running > 0);
// get content and remove handles
foreach($curly as $id => $c) {
$result[$id] = curl_multi_getcontent($c);
curl_multi_remove_handle($mh, $c);
}
// all done
curl_multi_close($mh);
return $result;
}
?>
上面的用法如下所示:
<?php
// An array of all the URLs to load:
$data = array(
'https://..',
'https://..',
'https://..'
);
// Load them now:
$r = multiRequest($data);
// r contains an array of responses.
print_r($r);
?>
也有类似的各种库。它使用CURL访问网站并获取HTTP代码-如果网站已启动,它将返回true;如果没有,则返回false
为什么不只卷曲标题并检查HTTP状态代码,而不是获取页面的全部内容?为什么不更新使用所有新的值,而不是执行多sql查询?为什么不看看multi-curl,在那里可以同时执行请求@JustOnUnderMillowns说@JustOnUnderMillowns只在标题上使用了curl?抱歉,并对问题进行了编辑以使其更清楚。我将研究multi-curl以同时发出请求-谢谢@frz3993。为了避免崩溃您的initcwnd,您确实应该调整批处理的大小(少于20个请求)。并设定请求的时限。谢谢-这是一个很大的帮助。