Cómo hacer muchas peticiones HTTP simultáneas en PHP

Uno de los problemas que habitualmente nos pueden frenar la carga de un sitio es si leemos mucha información de varios sitios de forma simultánea, como podría ser la lectura de varios feeds. Y es que habitualmente se usa la función file_get_contents() que tiene una cosa: es síncrona, es decir, hay que ejecutarla, esperar a que finalice, y volver a ejecutarla… pero ¿por qué esperar a qué acabe de leer para hacer otra llamada?

Para hacerlo podemos utilizar las funciones curl_multi_* que básicamente permiten hacer muchas llamadas cURL en muy poco tiempo. No es del todo asíncrono y en paralelo, pero casi casi se podría considerar como una opción.

El tiempo total de estas peticiones será la de la más lenta de todas, de forma que si tenemos algo como esto:

  • URL 1: 2,3 segundos
  • URL 2: 0,3 segundos
  • URL 3: 1,4 segundos
  • URL 4: 1,8 segundos
  • URL 5: 3,0 segundos

de la forma normal tardaríamos 8,8 segundos 8que es la suma de todos, aunque habría que sumarle los tiempos de conexión y desconexión), y de la forma que propongo se tardaría un poco más de 3,0 segundos, que es el tiempo de la más lenta de todas.

¿Cómo hacer esto?

<?php
function PeticionMultiple($urls, $opciones = array()) {
  $curly = array();
  $resultado = array();
  $pm = curl_multi_init();
  foreach ($urls as $id => $d) {
    $curly[$id] = curl_init();
    if(is_array($d) && !empty($d['url'])) {
      $url = $d['url']
    } else {
      $url = $d;
    }
    curl_setopt($curly[$id], CURLOPT_URL, $url);
    curl_setopt($curly[$id], CURLOPT_HEADER, 0);
    curl_setopt($curly[$id], CURLOPT_RETURNTRANSFER, 1);
    if (!empty($d['post'])) {
      curl_setopt($curly[$id], CURLOPT_POST, 1);
      curl_setopt($curly[$id], CURLOPT_POSTFIELDS, $d['post']);
    }
    if (!empty($opciones)) {
      curl_setopt_array($curly[$id], $opciones);
    }
    curl_multi_add_handle($pm, $curly[$id]);
  }
  $ejecutando = null;
  do {
    curl_multi_exec($pm, $ejecutando);
  } while($ejecutando > 0);
  foreach($curly as $id => $c) {
    $resultado[$id] = curl_multi_getcontent($c);
    curl_multi_remove_handle($pm, $c);
  }
  curl_multi_close($pm);
  return $resultado;
}
?>

Y el código de invocación:

<?php
$urls = array(
  'http://javiercasares.com/feed/atom/',
  'http://www.ethek.com/feed/atom/',
  'http://www.tumanitas.com/feed/'
);
$r = PeticionMultiple($urls);
print_r($r);
?>

Con esto, en principio, conseguiríamos múltiples peticiones para leer feeds de muchos sitios lo más rápido posible…

Relacionado: interesante la función EpicCurl del código EpiCode.

3 comentarios en “Cómo hacer muchas peticiones HTTP simultáneas en PHP”

  1. Hola!, he probado con esto, pero no me resulta. Me tira error en la línea 8 del código. Me podrías ayudar?

    Saludos,

Deja un comentario