Алексей Ц.
292 сообщения
#17 лет назад
Есть скрипт, выполняющий долгие и трудоемкие операции с удаленными файлами и заносящий результат в БД. Скрипт обычный пхп с параметром ГЕТ - идентификатор файла. Можно тупо набрать в браузере
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 сообщений
#17 лет назад
Нужно распараллеливать запуск скриптов. Способов несколько:

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, и даже на Bash. Но в этом случае придется синхронизировать работу скриптов более сложным образом, если конечно это необходимо.

На PHP больше ничего сделать не получится. Для таких целей нужно использовать Perl, Perl имеет все необходимые возможности для параллельной работы, в том числе и с внешними источниками данных.
Александрович И.
8 сообщений
#17 лет назад
Для PHP команды exec, shell_exec и подобные. Работают как под виндой так и под униксами.

Указываем путь к интерпретатору ПХП, путь к скрипту и через пробел значения параметров, т.е. в данном случае domen/script.php 3
В script.php параметр достаем через $argv...

Будет работать только на PHP, сборка которого разрешает использование команд exec*
Алексей Ц.
292 сообщения
#17 лет назад
Спасиб. Щас попробую.
Алексей Ц.
292 сообщения
#17 лет назад
Облом доступа ни к system, ни к exec нет.

Зато есть к Курлу. Кто ман подскажет?:unsure:
Вадим Т.
3240 сообщений
#17 лет назад
Цитата ("Tchokurov"):
Облом доступа ни к system, ни к exec нет.
Зато есть к Курлу. Кто ман подскажет?:unsure:


Нет доступа наверное потому что включен safe mode.

Насчет curl - нужен именно PHP 5, только в нем есть multi curl. Убедитесь что у Вас именно PHP 5. Примеры можно смотреть тут: (ну и дальше по ссылкам на функции curl_multi_* смотрите, слева).

Но вообще, повторюсь, для этой задачи лучше использовать Perl, наверняка он у Вашего хостера есть, и в нем все можно делать.
Алексей Ц.
292 сообщения
#17 лет назад
Если бы я еще знал перл Упустил я как то его. Спасиб
Александрович И.
8 сообщений
#17 лет назад
Некоторые хостеры разрешают собирать собственный PHP для своих нужд. Можно собрать с нужными функциями. Я именно так и сделал, однажды.
Алексей Ц.
292 сообщения
#17 лет назад
Проще на клиенте бат файл написать
Александр Е.
80 сообщений
#16 лет назад
Сделать можно, если будет открыт браузер на время поэтапной работы...
C помощью сессий.
При первом запуске в сессию пишем общее число запусков.
Перенаправляем на script.php?num=1
Если num < общего числа запусков, сохраненного в сессии, перенаправляем на num+1
(redirectим или c помощью хедер(Локейшн:...), или с помощь мета-тегов, например).
Если num=предельному числу - работа окончена.
Александр Е.
80 сообщений
#16 лет назад
Есть и более извращенный способ. Пишем php файл, который будет генерить нам кучу ифреймов. Даже можно их выводить пачками по десять штук. Что-то вроде
for($i=$page*$pagesize+1;$i<($page+1)*$pagesize;$i++) {
?>
<iframe src="script.php?num=<?php echo $i;?>"><br />
<?
}
Вадим Т.
3240 сообщений
#16 лет назад
Цитата ("Cord"):
Есть и более извращенный способ. Пишем php файл, который будет генерить нам кучу ифреймов.


Да я тоже предлагал подобное топикстартеру в приват, но оно убьет сервер если потоков будет хотя бы штук 700. Вот разве что пачками выводить не N штук... И постом выше вариант с сессиями может быть интересным, по крайней мере там тоже можно лимитировать количество потоков, которые запускаются одновременно (а остальные пока ждут).

Но опять-таки, в обоих случаях сохраняется недостаток - должен быть открыт браузер.
Дмитрий Сотник
24 сообщения
#16 лет назад
Мой вариант.
В браузер грузится джаваскрипт, простенький контроллер потоков, который запрашивает скрипт задачи на сервере через AJAX, при этом передает параметром в запросе "цель". 2 кнопки, старт\стоп и таблица, в которой мелькает состояние потоков

Весь вопрос в логике контроллера потоков, но там все просто Есть N слотов, как только слот освободился, в него ставятся задачи из очереди, если очередь не пуста. Условие выхода - все слоты и очередь пусты

Минус - "должен быть открыт браузер." Зато выглядит прикольно, когда мелькают статусы слотов и ползет прогрессбар
Алексей Ц.
292 сообщения
#16 лет назад
Короче договрился я таки с хостером. Мда. Вот код
<?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 сообщений
#16 лет назад
Хорошо бы перед unset($sockets); отработавший сокет вот так закрывать: fclose($socket);
Алексей Ц.
292 сообщения
#16 лет назад
Да, пожалуй.