Добрых Дел Мастер
С нами с 03.05.08
Сообщения: 3143
Рейтинг: 1227
|
Добавлено: 29/03/11 в 11:34 |
Гуру подскажите как реализовать нормальную многопоточность на пхп. Вот как я вижу: http://pastebin.com/LdSTxDNZ
Т.е. в кроне раз в 5 минут запускается файл run_10_proccess.php, который в 10 потоков запускает файл index.php. Если схема правильна то вопросы:
- если 10 потоков скрипта не укладываются в 5 минут то что будет? просто другой экземпляр run_10_proccess.php запуститься и ничего страшного не произойдет. так?
- как быть с логами самого скрипта который пускаем? в обычном виде в кроне такое:
*/5 * * * * php /scripts/index.php >> /logs/index.log
т.е. все сыпется в index.log. Для верхнего случая логи исполняемого скрипта будут сыпаться в лог run_10_proccess.log?
p.s. тема не касается ни курлов ни мультикурлов ни сокетов ни парсеров. Решение в общем виде.
|
|
пришел к победе коммунистического труда
|
0
|
|
|
www.phpdevs.com
С нами с 24.10.02
Сообщения: 16633
Рейтинг: 16105
|
Добавлено: 29/03/11 в 13:04 |
каждый поток создает файл времянку, по окончанию его удаляет. Если перед запуском файл есть - значит процесс уже работает. Ну или чуть сложнее, на наличие себя в процессах проверять.
|
|
Пишу на php/mysql/django за вменяемые деньги.
Обращаться в личку.
|
5
|
|
|
Криптопохуист
С нами с 05.04.03
Сообщения: 17158
Рейтинг: 6019
|
Добавлено: 29/03/11 в 13:08 |
|
|
|
|
С нами с 18.08.04
Сообщения: 6376
Рейтинг: 4430
|
Добавлено: 29/03/11 в 14:42 |
Вижу себе решение в изучение питона. В свое время тоже убил немало времени на пхп и многопточность и ничего лучше чем pcntl и задач во временых таблицах мускула не нашел. Но и это считай извратом. Питон прост и удобен
|
|
|
|
Криптопохуист
С нами с 05.04.03
Сообщения: 17158
Рейтинг: 6019
|
Добавлено: 29/03/11 в 15:12 |
|
|
|
|
С нами с 24.06.10
Сообщения: 2686
Рейтинг: 543
|
Добавлено: 29/03/11 в 16:46 |
pcntl_* тоже как бы ниразу не многопоточность, зато, позволяет нормально сигналами между своих процессов обмениваться.
кстати, использование flock-ов в качестве мъютексов, тоже не всегда прокатывает, ещё боле-менее, если файлы использовать просто в качестве флагов, но вот что бы обмениваться инфой между процессами и синхронизировать их таким способом, лучше всего использовать, как не банально, - мускул с эксключивным локом таблиц (lock tables) и вот уже таким обрахом писать/читать как состояния процессов, так и обмениваться информацией.
В общем, в пыхе нет нейтивных потоков (есть всякие патчи, но как бы хз насчёт ихнего будущего и вообще не слежу за всем, что допиливается кем-то на стороне, и может отсутствовать на обычном шареде) и их эмуляция - дело мутное и зависит от особенностей поставленной задачи (где просто узнать о существовании запущенного процесса, ну а где и полноценное interprocess communication понадобится), и посему моё имхо - юзать питон (ну или пёрл) в таких случаях
|
|
|
|
С нами с 08.02.03
Сообщения: 10564
Рейтинг: 5962
|
Добавлено: 29/03/11 в 21:07 |
все гараздо проще...
делаешь .sh пакет где у тебя
/usr/bin/php index.php
/usr/bin/php index.php
/usr/bin/php index.php
/usr/bin/php index.php
/usr/bin/php index.php
/usr/bin/php index.php
/usr/bin/php index.php
/usr/bin/php index.php
/usr/bin/php index.php
/usr/bin/php index.php
и его в крон с какой переодичностью сам решай...
первой строчкой делаешь mysql "select count from temportytable limit 1;"
потом
if ($count>10)
{
exit;
}
else
{
запросик "update temportytable set count=count+1;"
}
в конце скрипта
запросик "update temportytable set count=count-1;"
как только у тебя по крону запуститься 10 процессов (рабочих) скрипт будет тупо убиваться в начале
я лично смотрю еще la и %idle из top и по этим параметрам тоже запускаю или не запускаю скрипт получаю любое количество потоков и нагрузку ;)
|
|
|
|
С нами с 03.02.11
Сообщения: 842
Рейтинг: 301
|
Добавлено: 30/03/11 в 10:50 |
имхо, мускуль - не решение.
например, скрипт вылетит, не отметится в мускуле - и привет! будет считаться запущенным...
лучше лочить файлы flock($file, 2);
после отработки либо вылета скрипта файл анлочится автоматом. каждому потоку дать номер, правильно выставить set_time_limit - и вперед.
файл - пускач: main.php
Код: | $thread_dir = "threads/"; $max_threads = 10;
for($i=0; $i<$max_threads; $i++)
if(($tmp_file = fopen($thread_dir.$i, "w")))
if(flock($tmp_file, 2) == false) {
fclose($tmp_file);
echo 'Поток '.$i." уже работает\r\n";
continue;
}
else {
fclose($tmp_file);
//запускаем поток (я делал через хттп)
$fp = fsockopen('www.myhost.com', 80, $errno, $errstr, 1);
fputs($fp, "GET /do.php?thread=".$i." HTTP/1.0\r\nHost: myhost.com\r\n\r\n");
usleep(500);
fclose($fp);
}
|
ну а в do.php
Код: | ignore_user_abort(true);
set_time_limit(600); //0 не пойдет, а вдруг зависнет..
$thread = $_GET['thread'];
$in_work = fopen($thread_dir.$thread, "w");
flock($in_work, 2);
//тут делаем дело
flock($in_work, 3);
|
как-то так.
main.php пускай хоть каждую минуту, он запустит только не работающие потоки.
|
|
|
|
Криптопохуист
С нами с 05.04.03
Сообщения: 17158
Рейтинг: 6019
|
Добавлено: 30/03/11 в 11:00 |
mr. snatch писал: | pcntl_* тоже как бы ниразу не многопоточность, зато, позволяет нормально сигналами между своих процессов обмениваться. |
Да ладно? Или ты имеешь в виду треды? А ассемблерных вставок не хотел? )) Это ж пхп епт.
mr. snatch писал: |
лучше всего использовать, как не банально, - мускул с эксключивным локом таблиц (lock tables) и вот уже таким обрахом писать/читать как состояния процессов, так и обмениваться информацией. |
OMFG ) Слушай, ну ведь нормальный префорковый вебсервер Nanoweb. И никакого мускуля там нет.
JM писал: | все гараздо проще...
делаешь .sh пакет где у тебя
/usr/bin/php index.php
/usr/bin/php index.php
/usr/bin/php index.php
/usr/bin/php index.php
/usr/bin/php index.php
/usr/bin/php index.php
/usr/bin/php index.php
/usr/bin/php index.php
/usr/bin/php index.php
/usr/bin/php index.php
|
Бля, ну ацкие кодеры чисто собрались )) Эта шняга запустит последовательно 10 процессов. Один за другим. Охуенная многопоточность. Тогда уж так:
Код: |
#!/bin/bash
for i in `seq 10` ; do
/usr/bin/php index.php >/dev/null 2>&1 &
done
echo "10 processes started"
|
|
|
|
|
С нами с 24.06.10
Сообщения: 2686
Рейтинг: 543
|
Добавлено: 30/03/11 в 13:13 |
нановеб - не тот случай. Я говорю о решении, которое может работать на основной массе хостингов, и вот ПЫХ такими фитчами просто не располагает, и вот когда тебе нужно будет обмениваться определённой структурированной информацией между инстансами (которые могут и имеют полное право одновременно писать или читать какую-то свою часть), то просто flock-ов будет недостаточно, и гарантированный эксклюзивный lock достигается только блокировкой таблиц.
Причём здесь ассемблер вообще, я говорю всего-лишь об pthreads то есть многопоточности, а не форках, споувнах и прочей немногопоточности.
|
|
|
|
Добрых Дел Мастер
С нами с 03.05.08
Сообщения: 3143
Рейтинг: 1227
|
Добавлено: 30/03/11 в 15:30 |
спасибо господа всех заценил. наверно на локе файла остановлюсь
|
|
пришел к победе коммунистического труда
|
0
|
|
|
Криптопохуист
С нами с 05.04.03
Сообщения: 17158
Рейтинг: 6019
|
Добавлено: 30/03/11 в 15:34 |
mr. snatch писал: | Причём здесь ассемблер вообще, я говорю всего-лишь об pthreads то есть многопоточности, а не форках, споувнах и прочей немногопоточности. |
Вот ты деревянный. Какие pthreads ты хотел от Personal Home Page (ну или hypertext preprocessor - кому как нравится)?
|
|
|
|
С нами с 24.06.10
Сообщения: 2686
Рейтинг: 543
|
Добавлено: 30/03/11 в 16:39 |
Есть такое понятие - многопоточность, так же сущетсвует и то, что ты называешь многопоточностью эмулируя на ПЫХе. Вот то, про что говоришь ты - это форк, и с многопоточностью он ничего общего не имеет.
Да, есть различные эмуляции сабжа, но по каким таким признакам ты соотносишь мою деревянность и отсутствие сабжа в php, для меня загадка, я просто говорю о том, что если нужна действительно многопоточность, имеет смысл пересмотреть язык разработки.
выбирай выражения в общем )
|
|
|
|
Добрых Дел Мастер
С нами с 03.05.08
Сообщения: 3143
Рейтинг: 1227
|
Добавлено: 30/03/11 в 17:24 |
граждане просветленные кодеры, только не ругайтесь. итак вас мало
|
|
пришел к победе коммунистического труда
|
0
|
|
|
Добрых Дел Мастер
С нами с 03.05.08
Сообщения: 3143
Рейтинг: 1227
|
Добавлено: 01/04/11 в 22:30 |
вообщем написал хренатень такую. кстати опрашивать файл на заблокированность не надо. когда первый разлочит так сразу второй его залочит, итд. и файл открываем как 'a' а не как 'w'. w очищает файл. по сути пересоздает. наткнулся на обсуждение что типа где-то когда-то на каких-то платформах лок из-за этого могет не сработать
# Блокировка файла
class LockFile {
public function __construct() {
$this->file = fopen('1.lock', "a"); # открываем файл на запись
}
public function lock() {
flock($this->file, LOCK_EX); # блокируем файл на запись
echo 'момент лока: '. date('H:i:s');
}
public function unlock() {
flock($this->file, LOCK_UN); # разблокировка файла
echo 'момент разлока: '. date('H:i:s');
}
public function __destruct() {
fclose($this->file);
}
}
# Использование
$lockfile=new LockFile();
$lockfile->lock();
echo 'код';
$lockfile->unlock();
unset($lockfile);
|
|
пришел к победе коммунистического труда
|
0
|
|
|
С нами с 01.03.06
Сообщения: 629
Рейтинг: 620
|
Добавлено: 02/04/11 в 15:30 |
FXIX писал: | наткнулся на обсуждение что типа где-то когда-то на каких-то платформах лок из-за этого могет не сработать |
Да уже тут тоже перетирали про flock у пыха, например - PHP и mutex . Сами пыходелы в документации по flock тоже об этом возможном обломе предупреждают. Мне же как-то очень везет на системы с такими рпоблемами, почти каждая не блокирует как следует. А всего-то стоило внести в "язык" мьютексы и семафоры какие-либо.
|
|
|
|
С нами с 19.07.05
Сообщения: 318
Рейтинг: 401
|
Добавлено: 05/04/11 в 15:09 |
Писал многопоточные системы на php, все работало отлично.
По крону запускается загрузчик, который проверяет "ps | grep" есть ли управляющий процесс, если нет, запускает, есть - отваливает (опционально: если время выполнения управляющего процесса больше, чем заданное значение - kill & перезапуск).
Управляющий процесс в бесконечном цикле проверяет "ps | grep" сколько рабочих процессов трудятся, если меньше заданного значения, подбрасывают дровишек, а также проверяет флаги ресурсов (дату создания файла, имя которого - занятый ресурс, содержание - PID рабочего процесса) - если файл создан ранее чем time()-заданное значение максимального времени работы процесса, процесс прибивается, файл удаляется, в общий лог заносится замечание о таймауте.
Ну и скрипт для веб-мониторинга того, что происходит в системе, анализ лога ошибок, прибивание процессов руками, настройка констант таймаутов и кол-ва процессов.
|
|
|
|
Мотиватор :)
С нами с 06.05.09
Сообщения: 3028
Рейтинг: 607
|
Добавлено: 05/04/11 в 16:36 |
В своё время я потратил много времени на решение проблемы многопоточности в PHP. Создавать временные файлы или флаги в базе это ненадёжно, т.к скрипт может аварийно завершиться (например, исчерпает память) и не удалит временный файл. Ну и конечно же, перестанет запускаться.
В конце-концов, я пришёл к решению, которое у меня успешно работает в нескольких проектах. Здесь используется три скрипта - два шелл и один пхп. Первый шелл скрипт запускается из крона и служит для запуска всех тредов. Второй следит за тем, чтобы каждого треда было запущено не больше одного (причём он не "сломается", если предыдущий тред завершился аварийно). Ну и собственно, сам PHP скрипт, который делает нужную нам работу. Он получает в качестве параметра номер своего треда (в примере - от 1 до 10). Для каждого треда ведётся отдельный лог, куда записывается весь вывод PHP скрипта.
start_threads.sh (главный скрипт, который запускается каждую минуту в кроне):
Код: |
#!/bin/bash
# задаём путь, где у нас лежат скрипты, т.к этот скрипт запускается по крону
DIR=/path/to/your/scripts
cd $DIR
# кол-во одновременно запущенных тредов
max=10
count=1
while [ $count -le $max ]
do
$DIR/thread.sh $count &
count=$(( $count + 1 ))
done
|
thread.sh (он следит за тем, чтобы пхп треды не запускались больше одного раза):
Код: |
#!/bin/sh
DIR=/path/to/your/scripts
myname=`basename $0`
if test -r $DIR/$myname_$1.pid; then
RPID=$(cat $DIR/$myname_$1.pid)
if $(kill -CHLD $RPID >/dev/null 2>&1)
then
exit 0
fi
fi
# store my pid
echo $$ > $DIR/$myname_$1.pid
PHP=/usr/bin/php
cd $DIR
# запускаем PHP тред и передаём ему в качестве параметра номер его треда, вывод записываем в лог
$PHP $DIR/thread.php $1 >> $DIR/thread_$1.log
|
ну и собственно сам PHP скрипт (в данном примере ничего не делает, кроме как выводит "Тред такой-то запущен", что попадает в лог).
Код: |
<?php
// получаем номер треда
$thread = $argv[1];
// выводим тестовое сообщение, не забыв \n в конце, а то наш лог будет весь в одну строчку ;)
echo "Тред {$thread} запущен\n";
?>
|
|
|
|
|
С нами с 08.02.03
Сообщения: 10564
Рейтинг: 5962
|
Добавлено: 05/04/11 в 21:56 |
Pentarh писал: |
Бля, ну ацкие кодеры чисто собрались )) Эта шняга запустит последовательно 10 процессов. Один за другим. Охуенная многопоточность. Тогда уж так:
Код: |
#!/bin/bash
for i in `seq 10` ; do
/usr/bin/php index.php >/dev/null 2>&1 &
done
echo "10 processes started"
| |
Пост до конца перечитай...
|
|
|
|
С нами с 08.02.03
Сообщения: 10564
Рейтинг: 5962
|
Добавлено: 05/04/11 в 22:00 |
Походу тут никто не в курил в саму суть задача, а для чего вам ОДНОВРЕМЕННО 10 потоков? Что бы ждать пока они на 4х или 2х ядернике по сути поочереди отработаються?
|
|
|
|
Чингачгук, вождь красноглазых
С нами с 14.05.04
Сообщения: 4744
Рейтинг: 1824
|
Добавлено: 05/04/11 в 23:17 |
JM: Тоже начал читать топик (давно не заходил) и не понял - обычно люди стараются, чтобы задачи крона не запускались пачками, а напротив, как можно меньше грузили сервер. И как раз запускать их для этого лучше последовательно.
|
|
|
|
С нами с 19.07.05
Сообщения: 318
Рейтинг: 401
|
Добавлено: 05/04/11 в 23:24 |
JM писал: | Походу тут никто не в курил в саму суть задача, а для чего вам ОДНОВРЕМЕННО 10 потоков? Что бы ждать пока они на 4х или 2х ядернике по сути поочереди отработаються? |
Ну, например, собрать статсы с тысячи спонсоров, многие из которых могут отдавать их по 2-5 минут. Если собирать их последовательно, то можно легко в сутки не уложиться.
|
|
|
|
Чингачгук, вождь красноглазых
С нами с 14.05.04
Сообщения: 4744
Рейтинг: 1824
|
Добавлено: 05/04/11 в 23:43 |
|
|
|
|
С нами с 19.07.05
Сообщения: 318
Рейтинг: 401
|
Добавлено: 05/04/11 в 23:49 |
Dr.Syshalt писал: | Ну тогда не мильоны скриптов надо запускать |
Речь-то шла о десятке тредов.
curl_multi_* мне известен, как раз в приведенном мной примере такое решение не подходит, поскольку система писалась не с нуля на тыщу спонсоров, а по мере их добавления с фиг знает какого года.
|
|
|
|
С нами с 03.02.11
Сообщения: 842
Рейтинг: 301
|
Добавлено: 06/04/11 в 12:25 |
FXIX писал: | кстати опрашивать файл на заблокированность не надо. когда первый разлочит так сразу второй его залочит, итд. |
так речь шла о том, если файл залочен, то процесс запущен. зачем еще ожидающие процессы размножать?
alex.raven писал: | Создавать временные файлы или флаги в базе это ненадёжно, т.к скрипт может аварийно завершиться (например, исчерпает память) и не удалит временный файл. Ну и конечно же, перестанет запускаться. |
почему перестанет? хуй на временный файл, что не удалили, лок снимется с файла вместе с процессом.
|
|
|
|