php и потоки, как организовать параллельное обращение к методам объектов

slim-akim

Новичок
php и потоки, как организовать параллельное обращение к методам объектов

Здравствуйте!

Друзья, столкнулся с такой проблемой. Разрабатывается виджет "поиска авиабилетов". Источников данных несколько. Т.к. методы запроса данных отличаются, зачастую значительно,

отличаются, у разных поставщиков данных, то было принято решения для каждого источник написать свой класс. Т.е. параметры входные параметры для всех источников одинаковые, а

обработка (зарпрос, получение ответа, его разбор) разные. Все объекты источников возвразают одинаковой структуры массив. Массивы затем объединяются в один и выводятся

пользователю.
Сейчас это выглядит примерно таким образом:

PHP:
function getData($params)
{
	$source1 = new source1($params);
	$source2 = new source2($params);
	$source3 = new source3($params);
	
	
	$offers = array_merge( $source1->offers, $source2->offers, $source3->offers );
	return $offers;
}
Сейчас получается так, что запросы выполняются последовательно (во время создания объектов N), на это естественно уходит достаточно времени. Мне известно, что php как таковой,

многопоточность не поддерживает. Так же известны некоторые примеры эмуляции её с помощью proc_exec и curl_multi. Но не знаю как применить их именно для параллельного создания

объектов, или как вариант, параллельного выполнения функций этих объектов, например:

PHP:
function getData($params)
{
	$source1 = new source1();	
	$source2 = new source3();	
	$source3 = new source3();	
	

	// а вот это уже по потокам распределить
	$offers1 = $source1->getOffers( $params ); 
	$offers2 = $source2->getOffers( $params ); 
	$offers3 = $source3->getOffers( $params  ); 
	// дождаться выполнения последнего и объединить
	
	$offers = array_merge( $offers1, $offers2, $offers3);
	return $offers;
}
Если у вас есть опыт решения подобных вопросов, пожалуйста, поделитесь.
Буду благодарен за ваши советы,
спасибо.
 

slim-akim

Новичок
Автор оригинала: 440hz
откуда данные то запрашиваются?
у веб сервисов. для некоторых просто в виде параметров, для некоторых - soap, для некоторых запрос и в теле структурированный xml. ответы тоже приходят в xml.
 

mity

Новичок
Пишите скрипт, который обрабатывает только один источник, на входе POST или GET, на выходе массив через serialize
Пишите главный скрипт, который через multi_curl вызывает сколько вам угодно скриптов с единичным источником.
И всё будет прекрасно паралелиться
 

slim-akim

Новичок
Автор оригинала: mity
Пишите скрипт, который обрабатывает только один источник, на входе POST или GET, на выходе массив через serialize
Пишите главный скрипт, который через multi_curl вызывает сколько вам угодно скриптов с единичным источником.
И всё будет прекрасно паралелиться
Не совсем понял, как curl_multi будет вызывать скрипты. можно поподробнее/ссылку?
 

mity

Новичок
Примерно так, за точность не ручаюсь
PHP:
<?php
//Главный скрипт
function getData($params) 
{
  $curly = array();

  $mh = curl_multi_init();
 
  for($n=1;$n<=3;$n++){
    $curly[$n] = curl_init();
    curl_setopt($curly[$n], CURLOPT_URL, "http://service.ru/service$n.php");
    curl_setopt($curly[$n], CURLOPT_HEADER, 0);
    curl_setopt($curly[$n], CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($curly[$n], CURLOPT_TIMEOUT, 3000);
		
    curl_setopt($ch,CURLOPT_POST,TRUE); 
	
    curl_setopt($ch,CURLOPT_POSTFIELDS,"ar=".urlencode(seriliaze($params)));	//Вот здесь я до конца не уверен	
		curl_multi_add_handle($mh, $curly[$n]);
  }
 
  $running = null;
  do {
    curl_multi_exec($mh, $running);
  } while($running > 0);
 
 
 $ResultArray=array();
 
  foreach($curly as $id => $c) {
	
    $ResultArray = array_merge($ResultArray,unserialize(curl_multi_getcontent($c)));
		
    curl_multi_remove_handle($mh, $c);
  }
  curl_multi_close($mh);
  return $ResultArray;
}
?>

<?php
//скрипт запроса /service1.php 
$source = new source1();     
$offers = $source->getOffers( unserialize($_POST['ar']) ); 
echo serialize($offers);
?>

<?php
//скрипт запроса /service2.php 
$source = new source2();     
$offers = $source->getOffers( unserialize($_POST['ar']) ); 
echo serialize($offers);
?>
Выключайте везде magic_quotas, если входящих данных немного, для начала, лучше передавать их через GET

Здесь конечно нет обработки ошибок, а это в реальной программе необходимо
 

slim-akim

Новичок
Автор оригинала: mity
Примерно так, за точность не ручаюсь
...
Очень интересное решение, спасибо!
Попробую сделать так.

-~{}~ 20.05.10 16:42:

mity
Большое спасибо, получилось сделать способом, который вы предложили.
Предложения выдаются раза в 4-5 быстрее (15-20 секунд против 80-90).

-~{}~ 20.05.10 17:18:

2all если кому то понадобится, но примера mity будет недостаточно опишу чуть подробнее что откуда как:
написал скрипт, который за раз запрашивает данные с одного источника:
web-service.php

PHP:
...
Session::$v->requestData();
...
в классе Session

PHP:
public function requestData()
{
$object = new lib_service_Manager();
$object->execute();
}
в классе lib_service_Manager

PHP:
public function execute()
{

$service= $_POST['PartnerProgram'];
$params = json_decode( $_POST['Params'], true );
$result = $this->doRequestAvia($service, $params); // отправляем запрос нужному сервису
// внутри это функции находится switch, который, в зависимости от имени партнера создает объект (для каждого сервиса был создан свой класс, который с этим сервисом работает),
// который этому партнеру отправляет запрос, получает ответ, разбирает xml и возвращает ассоциативный массив
// для каждого сервиса этот процесс различается.
echo $result; // выводим json закодированный по urlencode

}
и теперь как используем эту штуку:

PHP:
public function preparationH($params)
{
$json = json_encode($params);

$services = array('x','y','z');

$curl=array();

$mh = curl_multi_init();

foreach ($services as $k=>$v)
{
$curl[$k] = curl_init();
curl_setopt($curl[$k], CURLOPT_URL, 'http://myhost/web-service.php');// т.е. фактически запросы я отправляю себе
curl_setopt($curl[$k], CURLOPT_HEADER, 0);
curl_setopt($curl[$k], CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl[$k], CURLOPT_TIMEOUT, 3000);
curl_setopt($curl[$k],CURLOPT_POST,TRUE);
curl_setopt($curl[$k],CURLOPT_POSTFIELDS,'PartnerProgram='.$v.'&Params='.urlencode( $json ));
curl_multi_add_handle($mh, $curl[$k]);
}



do
{
$status = curl_multi_exec($mh, $active);
}
while ($status === CURLM_CALL_MULTI_PERFORM || $active);

foreach ($services as $k1 => $v1)
{
$res[$k1] = curl_multi_getcontent($curl[$k1]);
curl_close($curl[$k1]);
curl_multi_remove_handle($mh, $curl[$k1]);
}
curl_multi_close($mh);



$offers = array();


foreach($res as $k => $v)
{

$unurl = urldecode($v);

if ($v!='Bad_Request')
{
$result = json_decode($unurl,true);

$offers = array_merge($offers, $result);

}


}

return $offers;
 
Сверху