Запуск скрипта в цикле
292 повідомлення
#18 років тому
Есть скрипт, выполняющий долгие и трудоемкие операции с удаленными файлами и заносящий результат в БД. Скрипт обычный пхп с параметром ГЕТ - идентификатор файла. Можно тупо набрать в браузереdomen/script.php?name=1
domen/script.php?name=2
domen/script.php?name=3
domen/script.php?name=4
В итоге у меня все работает. Но если файлов будет сотня?
Пришла в голову мысль, запустить один скрипт, который в цикле запустит эти скрипты (тупой require по сути). Сделал. Запускаются по очереди. Долго.
Может кто предложит простой вариант решения проблемы. Можно было бы через сокеты, но я сколько читал них не понял. Может пример какой простой с этим stream_set_blocking. На офф. сайте них нет.
3240 повідомлень
#18 років тому
Нужно распараллеливать запуск скриптов. Способов несколько:1. Для PHP есть такая возможность, называется pcntl, но она только для Unix/Linux, и не на всех сборках PHP это включено.
2. Для PHP5 можно использовать muti curl, тоже работает, но оно только получает данные с нескольких источников одновременно, а обрабатывать полученные данные все равно придется в основном потоке, хотя это уже намного (часто на порядок) быстрее.
3. Самый примитивный способ, для Unix/Linux: использовать команду system("/path_to_php/php /path_to_your_script/script.php name=1 &"

На PHP больше ничего сделать не получится. Для таких целей нужно использовать Perl, Perl имеет все необходимые возможности для параллельной работы, в том числе и с внешними источниками данных.
8 повідомлень
#18 років тому
Для PHP команды exec, shell_exec и подобные. Работают как под виндой так и под униксами.Указываем путь к интерпретатору ПХП, путь к скрипту и через пробел значения параметров, т.е. в данном случае domen/script.php 3
В script.php параметр достаем через $argv...
Будет работать только на PHP, сборка которого разрешает использование команд exec*
292 повідомлення
#18 років тому
Облом доступа ни к system, ни к exec нет. 
Зато есть к Курлу. Кто ман подскажет?:unsure:
3240 повідомлень
#18 років тому
Цитата ("Tchokurov"):Облом доступа ни к system, ни к exec нет.
Зато есть к Курлу. Кто ман подскажет?:unsure:
Нет доступа наверное потому что включен safe mode.
Насчет curl - нужен именно PHP 5, только в нем есть multi curl. Убедитесь что у Вас именно PHP 5. Примеры можно смотреть тут: посилання (ну и дальше по ссылкам на функции curl_multi_* смотрите, слева).
Но вообще, повторюсь, для этой задачи лучше использовать Perl, наверняка он у Вашего хостера есть, и в нем все можно делать.
8 повідомлень
#18 років тому
Некоторые хостеры разрешают собирать собственный PHP для своих нужд. Можно собрать с нужными функциями. Я именно так и сделал, однажды.
80 повідомлень
#18 років тому
Сделать можно, если будет открыт браузер на время поэтапной работы...C помощью сессий.
При первом запуске в сессию пишем общее число запусков.
Перенаправляем на script.php?num=1
Если num < общего числа запусков, сохраненного в сессии, перенаправляем на num+1
(redirectим или c помощью хедер(Локейшн:...), или с помощь мета-тегов, например).
Если num=предельному числу - работа окончена.
80 повідомлень
#18 років тому
Есть и более извращенный способ. Пишем php файл, который будет генерить нам кучу ифреймов. Даже можно их выводить пачками по десять штук. Что-то вродеfor($i=$page*$pagesize+1;$i<($page+1)*$pagesize;$i++) {
?>
<iframe src="script.php?num=<?php echo $i;?>"><br />
<?
}
3240 повідомлень
#18 років тому
Цитата ("Cord"):Есть и более извращенный способ. Пишем php файл, который будет генерить нам кучу ифреймов.
Да я тоже предлагал подобное топикстартеру в приват, но оно убьет сервер если потоков будет хотя бы штук 700. Вот разве что пачками выводить не N штук... И постом выше вариант с сессиями может быть интересным, по крайней мере там тоже можно лимитировать количество потоков, которые запускаются одновременно (а остальные пока ждут).
Но опять-таки, в обоих случаях сохраняется недостаток - должен быть открыт браузер.
24 повідомлення
#18 років тому
Мой вариант. В браузер грузится джаваскрипт, простенький контроллер потоков, который запрашивает скрипт задачи на сервере через AJAX, при этом передает параметром в запросе "цель". 2 кнопки, старт\стоп и таблица, в которой мелькает состояние потоков

Весь вопрос в логике контроллера потоков, но там все просто


Минус - "должен быть открыт браузер." Зато выглядит прикольно, когда мелькают статусы слотов и ползет прогрессбар

292 повідомлення
#18 років тому
Короче договрился я таки с хостером. Мда. Вот код<?php
require_once('db_connect.php');
// инициализация
$sockets = array();
$done = false;
$host = '****';
$result = mysql_query('************');
// приступаем к многопоточной работе
while (!$done)
{
// если число запущенных потоков меньше
// разрешенного максимума
// то запускаем потоки еще
if (10 > count($sockets))
{
if ($res = mysql_fetch_array($result))
{
// формируем запрос для передачи по сокету
$query = 'POST /pars_'.$_GET.'.php?id='.$res." HTTP/1.1\r\n";
$query = $query . "Content-Type: text/xml\r\n";
$query = $query . 'Host: ' . $host . "\r\n\r\n";
// создаем сокет, переводим его
// в неблокирующий режим и запускаем
// обработчик запросов
$errno = 0;
$error = '';
$socket = fsockopen($host, 80, $errno, $error, 30);
stream_set_blocking($socket, 0);
stream_set_timeout($socket, 3600);
fputs($socket, $query);
// запоминаем запущенный сокет
$sockets = $socket;
}
}
// читаем данные из сокета. формально они нам
// не нужны, но это позволяет
// отработать обработчкику запросов
reset($sockets);
while ($socket = current($sockets))
{
if (feof($socket))
{
// убиваем сокет, который отработал
unset($sockets);
}
else
{
// читаем данные из сокета
$temp = fgets($socket, 1000);
}
// обрабатываем следующий сокет
next($sockets);
}
// делаем небольщую задержку,
// иначе загруженность сервера
// приближается к 100 процентам
sleep(1);
// если нет активных сокетов, то можно выходить
if (count($sockets) == 0)
$done = true;
}
die;
?>
Может кому будет интересно. Хотя этот кусок кода я честно стыбрил из скрипта многопоточного спаммера.

3240 повідомлень
#18 років тому
Хорошо бы перед unset($sockets); отработавший сокет вот так закрывать: fclose($socket);