Многопоточность в php

Оффициальной нет, сразу скажу. Есть только многочисленные костылики. Примеры, в основном, будут полезны в сео софте.

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

Собсно, теория реализации.

Два скрипта — один поток, второй запускалка потоков. Поток делает свои дела, запускалка вычисляет, сколько потоков запустить и с какими параметрами.

Пример первый, запускает 20 потоков, если общее количество потоков ниже чем 10

<?php 

while(2 > 1):

$thCount = exec("ps a | thread.php | wc -l");
echo $thCount."\r\n";
 if($thCount < 10){
 for($i = 0; $i < 20; $i++){
 echo "launch thread\r\n";
 passthru("(php -f thread.php & ) >> /dev/null 2>&1");
 //sleep(1);
 }
 } else {
 sleep(5);
}
endwhile;

?>

Получается хрень, которая дозапускает потоки время от времени по условию. Потоков всегда разное число в разные промежутки времени и остановить их никак нельзя. Но, если некритичны все эти вещи, цикл вполне неплохо работает. Подходит, например, всякие регеры. При допилке можно держать нужное количество потоков с погрешностью +- 1. Для этого нужно просто динамически вычислять число запускаемых потоков. Да, и ps показывает три работающих потока при таком вызове, даже если нет ни одного. Один дает греп, второй сам скрипт, третий фиг знает кто.

Вариант 2.

Тут уже захотелось сделать более гибкую штуку. А именно — взять например 1к урлов и раздать их поровну N потокам.

<?php

$threads = 10;
$base = file("base.txt");

$perThread = ceil(count($base) / $threads);

for($i = 0; $i < $threads; $i++){
 if($i == 0) { passthru("(php -f thread.php '0|".$perThread."' & ) >> /dev/null 2>&1");    }
 if($i == $threads-1) { passthru("(php -f thread.php '".$perThread * $i."|".count($base)."' & ) >> /dev/null 2>&1");    }
 if(($i !== 0)&&($i !== $threads-1)) { 
 $start = $perThread * $i + 1;
 $end = $start -1 + $perThread;
 passthru("(php -f thread.php '".$start."|".$end."' & ) >> /dev/null 2>&1");    
 }
}
?>

Данный пример запускает поток с параметрами, который тот потом достает из массива $argv и использует. Такое вот разделение труда.

Взаимодействие между потоком и «мамой».
Тут у меня только теория. Думаю реализовать это через файлы. Поток создает файл с именем своей сессии (номера, пида), мама читает оттуда. Чтобы вывести инфу о потоках красиво и наглядно, думаю заюзать ncurses. Это сишная либа, на ней сделаны midnight commander, top. Доступна не только для пхп.

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

Саня, он же похапэ дуд , сразу обрубил — Я бы такие задачи не решал на php. Я тоже посматриваю в сторону других языков, думаю выучить что-то типа си, но пока я выучу, мне наверно уже ничего не надо будет. Есть вариант на питоне. И как раз в ридере попалась статья одного камрада, который начал изучать его и привел примерчик.
Вариант ,как по мне, не очень, бесконечные потоки и в пхп можно пускать. Но в посте увидел ссылочку, третий примерчик очень похож на то, что надо. Плюс питона еще в том, что в нем можно использовать графические либы типа gtk или qt, а это уже полноценные проги для енд-юзера а не софт для консольных гиков.


memcached php
установка memcached
скрипт опроса ajax

3.50 avg. rating (72% score) - 4 votes

30 комментариев

  • Многоточность действительно рулит, и я люблю про нее читать и ей заниматься.
    Но в данном случает действительно возникает вопрос: кроме чисто теоретического интереса, поможет ли это сайту?
    Ведь apache и так имеет несколько параллельных процессов.
    Так есть ли идеи, где php параллельность действительно была бы полезной?

    • Сандер, ты наверно немного не понял пост. Там совсем не про сайты. Там про различный софт на пхп.
      А в сайтах такая многопоточность не нужна, потому что, как ты верно заметил, там не php в чистом виде а mod_php апача. И сам апач уже согласно своему конфигу определяет число потоков.

  • Сорри, меня, наверное, на сайтах зациклило просто немного.
    Я думал, есть план применить это где-то в веб-кодинге.
    А так, я бы действительно на php такое не решал. Вообще, зачем писать софт на php? Тот же с уже будет на порядок лучше, а по базовому синтаксису особо-то и не отличается.

  • Ну как сказать, не отличается по синтаксису. Глянул я тут ncurses, сишную либу, немного мозг заклинило от такого «схожего» синтаксиса.  А пока я выучу тот же си хотя бы до уровня, на котором я знаю пхп, жизнь кончится.

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

  • Ну си тут тоже вполне родной (я, кстати, тоже под Линуксом). Компилировать, конечно, надо, но здесь это не проблема. Я-то просто научными задачами занимаюсь, высокая производительность нужна, php не подойдет. До этого сидел на спец-софте, а сейчас продвигаюсь в си — просто нет альтернативы…
    Ладно, сорри, что совсем от темы уже ушел

  • Состояния потоков итп — лучше через базу делать. Если в файл инфу дозаписываешь, то тебе его придется блокировать временно, тогда другие потоки будут либо ждать, либо дохнуть по time limit. С базой реально проще )) Если где-нить нароешь — была «спамилка от zumo» году в 06-07, там как раз это было реализовано.

    А вообще очень часто делается похожий механизм если тебе надо «долгоиграющий скрипт», а php совершает самоубийство через пару минут ))

  • >>Ну си тут тоже вполне родной
    Си он наверно везде родной ))
    А что за научные задачи, если не секрет?

  • Кирюха, блокировать это если все в один файл писать. Можно разнести по разным файлам, а имена привязать к сессии например или к пиду. И писать можно не через fopen а через exec (» echo text >> file») , так не они не перезатираются.

    >>а php совершает самоубийство через пару минут

    Эт как настроен смотря. На серверах по бесконечному циклу может сутками крутится, на хостингах рубят обычно.

     

  • Дык а база что? таблица с данными по которым отрабатывать, поток при запуске забирает сколько ему надо, метку в ней оставляет, что работает с ними и поехали, а новые потоки данные дергают у которые «свободны» итд итп. И с админкой, если потребуется, проблем меньше с написанием 🙂 Но это дело вкуса :))

    >На серверах по бесконечному циклу может сутками крутится, на хостингах рубят обычно.
    Я не о том. PHP5 на это уже не тестилось, а с PHP4 было подозрение, что оно переменную хранит в оперативке, потом я ее затираю, оно ее оттуда затирает, но место это больше занимать не хочет и через некоторое время оперативка «как бы» для него заканчивается. Хотя не скрою, что в те времена руки у меня были кривыми 🙂

  • База это лишний софт. Админка так вообще не нужна, как по мне.
    >>Я не о том. PHP5 на это уже не тестилось, а с PHP4 было подозрение, что оно переменную хранит в оперативке
    Ты про out of memory range?

  • Ога. То есть изначально всего хватало, пользовался unset-ом для всего ненужного, но через минут 5-10 начиналось. Причем в то же время у cgi таких проблем не было (вплоть до того, что tds-ки выносливые народ старался писать на сях).

  • > А что за научные задачи, если не секрет?
    Физика. Расчет взаимодействия элементарных частиц. Связано с коллайдером.
    Если интересно, мои программы тут: http://science.sander.su (сайт убог и не раскручивается, но кто нужно — знают, а это и цель)

  • >>Связано с коллайдером.
    Уважуха ))

  • http://habrahabr.ru/blogs/python/78267/
    многопоточность в питоне )

  • Многопоточность вещь нужная..особенно если надо пропарсить чей то сайт)))..или допустим цены в инте-магазине перетырить так сказать)))

  • ГГГ =) Парсер писал =))
    Я реализовывал что-то похожее, только процессами управлял крон-скрипт, который постоянно запускался, и следил за количеством, статусами (сдох, завис и т.д.). А процессы и исполняемые файлы хранились в базе.
    Кстати, можно и проще выполнять команды в консоль из PHP файла.
    $r = ‘some_command’;
    $output = `r`;
    Достаточно тильдами закавычить, а в $output будет респонс валится. Оно выполнится.

  • codeator, я за статусом через пид-файл следил. На файлах проще система — где угодно сразу можно запустить. А про тильды я знаю, но не всегда получается запускать через system_exec, иногда проходит только passthru, иногда exec. Хз почему так, но вот бывает такой затуп

  • Гораздо проще и функциональнее реалзиовать такое на PCNTL-функциях

  • Всем привет, до моего уровня знания пхп вам всем еще деградировать и деградировать) простите за черный юмор) как вы могли понять, я ни хрена не понимаю в php поэтому у меня просьба, обюясните пожалуйста как действуют в приведенном коде параметры функции passthru или скорее процедуры,тк она не возвращает ни какого значения

    • она выполняет внешнюю команду по запуску скрипта

  • это я понял из описания в мануалах, мне не понятны параметры, например откуда взялось вот это: php -f, вот это: &, или вот это:>> /dev/null 2>&1

    • Это параметры запуска пхп скрипта в консоли — php -f(foreground), >> /dev/null 2>&1 значит весь вывод подавлять в девнулл

  • А вот на примере: <? $file = file_get_contents('http://data.alexa.com/data?cli=10&dat=snbamz&url=&#039;.$url);
    preg_match('/\/si’, $file, $alexa);
    echo $alexa[2] ;
    $arank=$alexa[2];
    ?>
    Как реализовать, чтобы сразу несколько клиентов на одном сервере выполняли?

    • несколько клиентов на одном сервере выполняли?

      немного не понял вопроса

  • У меня этот скрипт расположен на сайте http://pr-ic.ru/, и пока он ваполнеется, другие его запустить не могут.

    • Чет фигня какая-то, при обращении по http там апач уже пускает скрипты и он отвечает за форки.

  • Вот пример относительно нормальной реализации многозадачности в PHP
    http://tester.in/rt/task_test.php

  • Простите, а в базу вы тоже шелом ходите? Типа

    passthru(‘mysql -uroot -pmyHardPassword -hlocalhost -e «select * from myDB.myTbl limit 3″‘);

    работает, ага. Правда потом сложности с парсингом…

    • несколько не понял вопроса
      для работы с базой есть встроенная либа, для работы с многопоточностью нет, отсюда и велосипеды
      и какие проблемы с парсингом возникают?

  • В парсерах организовываю многопоточность через аякс. Запускающий яваскрипт контролирует таймаут запуска и число запущенных потоков. Все просто, кнопки управления переменными яваскрипта влияют на таймаут/количество потоков. Второй скриптик пхп отвечает за поток.

css.php