使用cron运行Foreach循环的PHP脚本-花费的时间太长-如何更快地完成

使用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创建一个网站监控webapp。要监视的网站的URL存储在MySQL表中。脚本通过cron每分钟运行一次——它在所有网站和foreach URL中循环,它使用CURL访问网站,使用CURLINFO_HTTP_代码获取HTTP代码——如果网站正常运行,则返回true,否则返回false

脚本运行正常-一两个网站的运行时间为毫秒,而20个网站的运行时间平均为2-15秒。我可以看到,当添加更多的站点时,这将导致问题——理想情况下,我需要监控数千个站点,用户能够添加自己的站点

我曾经考虑过,当用户添加一个要监视的站点时,会为每个URL添加单独的cron和文件,但是我不确定该如何进行,而且我可以预见在共享服务器上工作时会出现一些问题

那么我该怎么做呢,还是有更好的方法我还没有想到呢

<?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个请求)。并设定请求的时限。谢谢-这是一个很大的帮助。