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

Discussion in 'PHP' started by genom--, 27 Oct 2007.

Thread Status:
Not open for further replies.
  1. genom--

    genom-- Elder - Старейшина

    Joined:
    9 Jul 2006
    Messages:
    668
    Likes Received:
    416
    Reputations:
    288
    в общем мой вопрос касается сабжа -- есть какиенибуть нормальные схемы реализации многопоточности в php -- искал в нете но там одно извращенство типо создания нескольких сокетов и последовательного чтения из каждого и тд

    ну в общем если есть у когонить инфа желательно с примером - если будет ;)
     
  2. Stefun

    Stefun Elder - Старейшина

    Joined:
    19 Nov 2006
    Messages:
    48
    Likes Received:
    29
    Reputations:
    11
    Первый раз слышу что в пхп можно сделать многопоточность, мда...
    В пхп нельзя это реализовать
     
  3. inv

    inv Banned

    Joined:
    3 Aug 2007
    Messages:
    261
    Likes Received:
    143
    Reputations:
    -58
    точно не знаю....
    в любом случае два варианта
    если ты работаешь с сокетами
    1.асинхронные сокеты (то что ты и сказал - перебирать); curl_multi_init();
    2.использовать библиотеки там есть многопроцессорность (никакой информации у меня нет,могу ошибаться)

    ***
    pcntl_fork()
     
    #3 inv, 27 Oct 2007
    Last edited: 27 Oct 2007
  4. EST a1ien

    EST a1ien Elder - Старейшина

    Joined:
    2 Apr 2006
    Messages:
    249
    Likes Received:
    48
    Reputations:
    16
    Думаю что кроме того сто ты привел
    Врядли чтото прокатит
     
  5. KSURi

    KSURi tnega AOLPS

    Joined:
    6 Jun 2006
    Messages:
    458
    Likes Received:
    219
    Reputations:
    357
    пора бы уже знать, что НЕТ
     
  6. genom--

    genom-- Elder - Старейшина

    Joined:
    9 Jul 2006
    Messages:
    668
    Likes Received:
    416
    Reputations:
    288
    я знаю что нет -- но тем не менее мб ченить кроме этих сокетов -- придумали уже
     
  7. KSURi

    KSURi tnega AOLPS

    Joined:
    6 Jun 2006
    Messages:
    458
    Likes Received:
    219
    Reputations:
    357
    Пул неблокирующих сокетов - это не многопоточность
    Ничего не придумали и врядли придумают
     
  8. banned

    banned Banned

    Joined:
    20 Nov 2006
    Messages:
    3,324
    Likes Received:
    1,193
    Reputations:
    252
    перебирать != многопоточность
     
  9. DIAgen

    DIAgen Banned Life!

    Joined:
    2 May 2006
    Messages:
    1,055
    Likes Received:
    376
    Reputations:
    460
    Много порочность врятли получиться но есть два выхода что можно сделать и оба под php5...
    1) Это использовать url_multi_exec
    PHP:
    <?php
    // create both cURL resources
    $ch1 curl_init();
    $ch2 curl_init();

    // set URL and other appropriate options
    curl_setopt($ch1CURLOPT_URL"http://www.google.com/");
    curl_setopt($ch1CURLOPT_HEADER0);
    curl_setopt($ch2CURLOPT_URL"http://www.php.net/");
    curl_setopt($ch2CURLOPT_HEADER0);

    //create the multiple cURL handle
    $mh curl_multi_init();

    //add the two handles
    curl_multi_add_handle($mh,$ch1);
    curl_multi_add_handle($mh,$ch2);

    $running=null;
    //execute the handles
    do {
        
    curl_multi_exec($mh,$running);
    } while (
    $running 0);
    //close the handles
    curl_multi_remove_handle($mh,$ch1);
    curl_multi_remove_handle($mh,$ch1);
    curl_multi_close($mh);
    ?>
    2) Рассмотри вот этот скрипт
    PHP:
    <?php
    if (!defined("MD_DEBUG")) define("MD_DEBUG"false);
    function 
    get_chanked($stream) {
       
    $content "";
       do
       {
          
    $len trim(fgets($stream10));
          if (
    MD_DEBUG) echo "Find lable 0x$len<br>\n";
          if (
    $len === false || !preg_match("|[0-9a-f]+|i"$len))
          {
             if (
    MD_DEBUG) echo "Failure getting content<br>\n";
             return 
    "";
          }
          else
          {
             
    $len hexdec($len);
             if (
    MD_DEBUG) echo "Reading $len byte<br>\n";
          }
          if (
    $len 0)
          {
             
    $readed 0;
             while(
    $readed $len 2)
             {
                
    $buffer fgets($stream);
                
    $readed += strlen($buffer);
                
    $content .= $buffer;
             }
          }
        } while(
    $len 0);
        return 
    $content;
        }
    function 
    MyDownload ($urls$timeout 30) {
        
    $streams = array();
        
    $result = array();
        foreach(
    $urls as $url)
        {
           
    $host parse_url($urlPHP_URL_HOST);
           if (
    $host === null)
           {
              if (
    MD_DEBUG) echo "Host in '$url' is not correct<br>\n";
              continue;
           }
           
    $port parse_url($urlPHP_URL_PORT);
           
    $stream = @stream_socket_client(// Если не удается законнектится то выводится Warning, а он нам тут совершенно не нужен
              
    "tcp://$host:".($port === null "80" $port),
              
    $errno$errstr$timeout,
              
    STREAM_CLIENT_ASYNC_CONNECT|STREAM_CLIENT_CONNECT); // Асинхронное соединение, что бы не ждать коннекта...
           
    if ($errno 0)
           {
              if (
    MD_DEBUG) echo "Error connectiong to $url$errstr($errno)<br>\n";
              
    // либо еще что-нибудь делаем. Пишем в логи итп...
              
    continue;
           }
           
    stream_set_blocking($stream0); // Для всех потоков ставим режим non-blocking, что бы не ждать когда данные будут доступны для чтения/записи
           
    $streams[$url] = $stream;
        }
        
    $toException $toRead $toWrite $streams// Два массива потоков, для чтения и для записи. Для чтения можно сразуже задавать, т.к. все равно они не будут доступны пока не будет послан запрос
        
    do
        {
           
    $rStreams $toRead;
           
    $wStreams $toWrite;
           
    $eStreams $toException;
           
    $num = @stream_select($rStreams$wStreams$eStreams0); // Выбираем какой-нибудь поток. Последний параметр 0 - не ждать таймаута 
        
           
    if ($num 0// Если $num == 0, то можно добавить в общий массив новых потоков, что бы не stream_select не простаивал, но я не стал этого делать
           
    {
              if (
    count($wStreams) > 0)
              {
                 foreach(
    $wStreams as $write)
                 {
                    
    $url array_search($write$streams);
                    
    $host parse_url($urlPHP_URL_HOST);
                    
    $request "GET $url HTTP/1.1\r\nAccept: */*\r\nnAccept-Language: en-us\r\nPragma: no-cache\r\nUser-Agent: Mozilla/4.0 (compatible; MSIE 6.0)\r\nHost: $host\r\nConnection: Close\r\n\r\n";
                    if (
    MD_DEBUG) echo "Sending request for $url<br>\n$request";
                    
    fwrite($write$request);
                    unset(
    $toWrite[array_search($write$toWrite)]); // Запрос послан, больше не надо выбирать поток для записи
                 
    }
              }
              if (
    count($rStreams) > 0)
              {
                 foreach(
    $rStreams as $read)
                 {
                    
    $url array_search($read$streams);
                    
    $key array_keys ($urls$url); $key $key[0];
                    if (
    MD_DEBUG) echo "Getting data for $url<br>\n";
                    
    $isChunk false;
                    
    $charset "";
                    
    $result[$key][0] = "";
                    while((
    $header fgets($read)) != "\r\n") {
                        if (!(
    strpos($header"Content-Type")===false)) if (!(strpos($header"charset=")===false)) $charset substr($headerstrpos($header"charset=")+8);
                        else 
    $charset "default";
                        if (
    preg_match("|Transfer-Encoding:\s+chunked|i"$header)) $isChunk true;
                     }
                    if (
    $isChunk$result[$key][0] = get_chanked($read);
                    else while (!
    feof($read)) $result[$key][0] .= fread($read1024);
                    
    $result[$key][1] = $charset;
                    unset(
    $toRead[array_search($read$toRead)]); // Ответ получен, поток не нужен больше
                 
    }
              }
              if (
    count($eStreams) > 0)
              {
                 foreach(
    $eStreams as $exception)
                 {
                    
    $url array_search($exception$streams);
                    if (
    MD_DEBUG) echo "Fail getting data for $url.<br>\n";
                    
    // Здесь так же кричим, что сервер вернул не то что ожидали и выкидываем этот поток из стека
                 
    }
                 unset(
    $toRead[array_search($exception$toRead)]);
                 unset(
    $toWrite[array_search($exception$toWrite)]);
                 unset(
    $toException[array_search($exception$toException)]);
              }
           }
        } while(
    count($toRead) > 0); // Читать нечего больше
        
    return $result;
    }
    $urls = array(
    "yandex"=>"http://www.yandex.ru/yandsearch?text=Превед",
    "whois"=>"http://www.service-whois.ru/?domain=mail.ru"
        
    );
    $sites MyDownload ($urls);
    $yandex1 $sites["yandex"][0];
    $yandex2 $sites["yandex"][1];
    ?>
    Даный скрипт будет работать только в php5, не много поточность... но работает быстро и эффективно...
     
    #9 DIAgen, 28 Oct 2007
    Last edited: 28 Oct 2007
  10. genom--

    genom-- Elder - Старейшина

    Joined:
    9 Jul 2006
    Messages:
    668
    Likes Received:
    416
    Reputations:
    288
    лан спс всем -- будем думать
     
  11. DIAgen

    DIAgen Banned Life!

    Joined:
    2 May 2006
    Messages:
    1,055
    Likes Received:
    376
    Reputations:
    460
    Второй пример можно переделать под php 4, заменив работу функции stream_socket_client на fsockopen или Socket


    P.S. Вот уже есть готовый класс для работы с потоками http://multi-downoader.googlecode.com/svn/trunk/Downloader/
     
    #11 DIAgen, 28 Oct 2007
    Last edited: 28 Oct 2007
  12. ZaCo

    ZaCo Banned

    Joined:
    20 Jun 2005
    Messages:
    737
    Likes Received:
    336
    Reputations:
    215
    тема обсуждалась http://forum.antichat.ru/showthread.php?p=200343
    и еще, СТАНДАРТНЫХ средств в пхп для многопоточности нет. но если вам необходимо качественное (все приведенные методы медленные и в общем случае нерабочие) решение, то теоретически можно написать свой модуль.
    а запускать функции через это http://man.chinaunix.net/develop/php/php_manual_zh/html/zend.calling-user-functions.html
    к сожалению как устроены переменные в пхп не знаю, поэтому утвержадть о работоспособности такого способа не могу.
     
  13. _Great_

    _Great_ Elder - Старейшина

    Joined:
    27 Dec 2005
    Messages:
    2,032
    Likes Received:
    1,119
    Reputations:
    1,139
    ядро ОС перебирает готовые потоки, выделяя каждому квант времени. утверждение неверно =)))

    ( расценивать как шутку )
     
    1 person likes this.
  14. groundhog

    groundhog Elder - Старейшина

    Joined:
    12 May 2007
    Messages:
    1,159
    Likes Received:
    425
    Reputations:
    180
    Многопоточность в PHP есть! Почему всё время забывают про pcntl_fork? Другое дело, что такое возможно реализовать только на Unix платформе, и если PHP включён не модулем, а как CGI.
     
    1 person likes this.
  15. fucker"ok

    fucker"ok Elder - Старейшина

    Joined:
    21 Nov 2004
    Messages:
    580
    Likes Received:
    279
    Reputations:
    91
    >Почему всё время забывают про pcntl_fork?
    Потому-что в среднем php процесс занимает 16мб памяти и можно посчитать на сколько хватит памяти, если форкать много раз :)
     
  16. ZaCo

    ZaCo Banned

    Joined:
    20 Jun 2005
    Messages:
    737
    Likes Received:
    336
    Reputations:
    215
    2groundhog
    >>СТАНДАРТНЫХ средств в пхп для многопоточности нет
    и еще, поток это единица процесса, адресное пространство, за исключением стека и регистров, что для php не надо, одно и это в общем-то выгодное для определенных задач отличие от двух родственных процессов, поэтому если ищут именно решение для организации многопоточной программы не нужно давать решение для другой задачи.
     
  17. groundhog

    groundhog Elder - Старейшина

    Joined:
    12 May 2007
    Messages:
    1,159
    Likes Received:
    425
    Reputations:
    180
    Бред какой-то...

    Это вопрос конфигурации. ТС не ставил определённой задачи, а искал метод реализации - я его и предоставил.
     
  18. _Great_

    _Great_ Elder - Старейшина

    Joined:
    27 Dec 2005
    Messages:
    2,032
    Likes Received:
    1,119
    Reputations:
    1,139
    вроде как в линуксе потоки реализованы как процессы.
     
  19. nerezus

    nerezus Banned

    Joined:
    12 Aug 2004
    Messages:
    3,191
    Likes Received:
    729
    Reputations:
    266
    Это не потоки. Учи матчасть.

    Многопоточности в PHP нету и не будет. Тема закрыта.
     
    #19 nerezus, 28 Oct 2007
    Last edited by a moderator: 28 Oct 2007
    1 person likes this.
  20. _Great_

    _Great_ Elder - Старейшина

    Joined:
    27 Dec 2005
    Messages:
    2,032
    Likes Received:
    1,119
    Reputations:
    1,139
    нер, про матчасть стоит почитать имхо тебе.

    http://en.wikipedia.org/wiki/Light-weight_process
    читай это и все ссылки из See Also
     
Thread Status:
Not open for further replies.