带有使用cron运行的Foreach循环的PHP脚本 - 需要太长时间 - 如何更快地完成它

时间:2017-02-20 17:00:24

标签: php performance cron

我正在尝试使用PHP创建一个监控webapp的网站。要监视的网站的URL存储在MySQL表中。脚本每分钟通过cron运行 - 它遍历所有网站和foreach URL,它使用CURL访问网站,CURLINFO_HTTP_CODE获取HTTP代码 - 如果网站已启动则返回true,否则返回false。

脚本工作正常 - 有一个或两个网站需要几毫秒才能运行,但有20个网站平均需要2-15秒才能运行。我可以看到,当添加更多网站时,这会导致问题 - 理想情况下,我需要监控数千个网站,用户才能添加自己的网站。

当用户添加要监控的网站时,我已经考虑过为每个网址添加单独的crons和文件 - 但是我不知道如何去做,我可以预见到一些问题,因为我正在努力共享服务器。

那么我应该如何解决这个问题,还是有一种我没有想过的更好的方法?

<?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


       }
}

1 个答案:

答案 0 :(得分:0)

并行运行请求

PHP在并行任务方面通常不是很好,但它肯定是可能的。简而言之,HTTP请求是一项非常缓慢的任务 - 在您的服务器和远程服务器之间有很多来回。 PHP通常被设计为顺序 - 这意味着它一次只做一件事。因此,它最终会浪费很多时间,只需等待远程服务器响应,一次一个。

  • 发送一个请求
  • 等待年龄
  • 发送一个请求
  • 等待年龄
  • 等<!/ LI>

您要做的是确保一起发出大量请求,然后同时等待它们。幸运的是,PHP提供multi curl来做到这一点。

以下是this great post关于主题的示例函数:

<?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);

?>

还有各种类似Parallel Curl的库。