Авторские статьи Эмуляция многопоточности в PHP

Discussion in 'Статьи' started by S0meT1me, 19 Sep 2010.

  1. S0meT1me

    S0meT1me Member

    Joined:
    2 Jun 2009
    Messages:
    0
    Likes Received:
    9
    Reputations:
    -5
    I ВСТУПЛЕНИЕ

    PHP относится к языкам программирования, в которых поддержка многопоточности отсутствует. Но, существует немало задач, где она необходима. В рамках тематики данного форума это могут быть брутеры, спамеры, граберы, чекеры, инвайтеры, гулялки, заливщики.

    Сразу отмечу, эмулировать многопоточность будем для работы с сетью, не для вычислительных процессов и прочего (ИМХО - здесь PHP не пригоден как интерпритируемый язык в связи со скоростью его выполнения).

    Итак, рассмотрим способы реализации многопоточности в ПХП.

    1. Многопоточность можно реализовать внутри вашего скрипта, создав список неблокирующих сокетов и переодически проверяя отработал поток или нет.
    Такой подход подробно рассмотрен здесь . Стоит так же отметить, такой же подход использует класс функций multi_ библиотеки CURL.

    2. Второй метод основан на эмуляцции многопоточности, используя многозадачность. Другими словами, наш скрипт просто запускает нужное число процессов, распределяя между ними входные данные нужным образом. Этот метод впервые был предложен на ачате здесь , так же интересная реализация этого метода предложена здесь .

    Я пошёл по второму пути, развил и доработал его. Разработанный скрипт распределяет входные данные, может работать с несколькими исполняемыми скриптами одновременно, собирает результаты работы скриптов по их завершению.

    II РЕАЛИЗАЦИЯ

    Функция для запуска эмуляции многопоточности

    PHP:
    threads_create
        
    $threads,             //число потоков
        
    $copy_files,         //файлы, нужные для работы каждого потока
        
    $create_files,         //исходные данные, которые нужно распределить между потоками
        
    $run_files,         //исполняемые файлы в рамках каждого потока
        
    $implode_files        //результирующие данные, сформированные каждым из потоков, которые нужно собрать в 1 файл
    )
    Вкратце алгоритм работы:
    В результате работы функция создаёт папки для каждого потока, копирует туда нужные для работы файлы, разделяет данные между этими папками и запускает каждый исполняемый скрипт. По завершению работы скрипт сохраняет результирующие данные в файл в своей папке, а когда все скрипты отработают, софт соберёт результирующие данные из указанных файлов и разместит их в файле с тем же именем в папке со скриптом. Все созданные промежуточные файлы и папки удаляются.

    PHP:
    function threads_create$threads$copy_files$create_files$run_files$implode_files=array() ) {

        
    $cfs    = array();
        foreach( 
    $create_files as $fname => $content ) {
            if( !
    is_array$content ) ) {
                
    $content    file2array$fname );
            } else {
            }
            
    $cfs$fname ] = array_rand_slice$content$threads );
        }
        
        
    $bat    "@echo off\ncd thread0\n";
        
    $tdir    'threads-' randstr(5);
        
    mkdir$tdir );
        
    chdir$tdir );
        
        for( 
    $i 0$i $threads$i++ ) {
            
            
    $dir 'thread' $i;
            
    mkdir$dir );
            
            foreach( 
    $copy_files as $fname_from => $fname )
                
    copy'../' $fname_from$dir '/' $fname );
            
            foreach( 
    array_keys$cfs ) as $fname 
                
    file_put_contents$dir '/' $fnamestr_replace"\n\n""\n"implode"\n"$cfs [$fname] [$i] ) ) );
            
            
    $bat .= "cd ..\\thread{$i}\n";
            foreach( 
    $run_files as $fname => $params 
                
    $bat .= "start php $fname $params\n";
        }
        
        
    file_put_contents'run.bat'$bat );
        
    exec('run.bat');
        
    unlink('run.bat');
            
        foreach( 
    $implode_files as $if ) {
            
    $contents = array();
            for( 
    $i 0$i $threads$i++ ) {
                
    $contents []= trimfile_get_contents'thread' $i "\\" $if ) );
            }
            
    file_put_contents"..\\$if"implode"\r\n"$contents ), FILE_APPEND  );
        }

        for( 
    $i 0$i $threads$i++ ) {
            
    $dir 'thread' $i;
            
            foreach( 
    array_mergearray_keys$cfs ), array_keys$copy_files ) ) as $fname )
                
    unlink$dir '/' $fname );
            
    rmdir$dir );
            
        }
        
    rmdir$tdir );
    }
    function 
    randel$array ) {
        return 
    $arraymt_rand0count($array) - ) ];
    }
    function 
    randsymb() {
        
    $symbs 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
        
    $rand mt_rand(0,strlen($symbs)-1);
        return 
    $symbs{$rand};
    }
    function 
    randstr($len) {
        for(
    $i=0;$i<$len;$i++) {
            
    $str .= randsymb();
        }
        return 
    $str;
    }
    function 
    file2array$filename ) {
        
    $array = array();
        foreach( 
    file$filename ) as $row ) if( $row trim$row ) ) {
            
    $array []= $row;
        }
        return 
    $array;
    }
    function 
    array_rand_slice$array$amount ) {
        
    shuffle$array );
        
    $sliced    = array();
        
    $step    floorcount$array ) / $amount );
        for( 
    $i 0$i count$array ); $i += $step ) {
            
    $sliced    []= array_slice$array$i$step );
        }
        return 
    $sliced;
    }
    III ПРИМЕР

    Рассмотим эмуляцию многопоточности на примере выложенного мню ранее чеккера ВК аккаунтов. Можете скачать и поганять, что бы увидеть как это всё работает.

    Чеккер распостраняется в виде 3-х файлов:
    +accs.txt - файл с аккаунтами на чек
    + do.php - собственно чекер, однопоточный,
    + make.php - запускает чек ( php make.php ЧИСЛО_ПОТОКОВ )
    PHP:
    if( $threads $argv[1] ) {
        include_once(
    '../includes/lib.vk.php');
        include_once(
    '../includes/lib.thread.php');
        
    threads_create
            
    $threads,                             //указываем число потоков, считав его предварительно как первый параметр командной строки
            
    array(
                
    'do.php'    => 'do.php',        //какие файлы копировать в папку к каждому потоку
            
    ),
            array(
                
    'accs.txt'    => 'accs.txt',        //какие файлы содержат данные, что надо равномерно распределить между всеми потоками
            
    ),
            array(
                
    'do.php'    => '',                 //исполняемые файлы с набором параметров
            
    ),
            array(
                
    'accs.good.txt',                //файл гуд акков, который надо собрать в результате работы каждого из потоков
                
    'accs.bad.txt'                    //файл бед акков
            
    )
        );
    Спасибо за внимание.
     
    #1 S0meT1me, 19 Sep 2010
    Last edited: 19 Sep 2010
    1 person likes this.
  2. Catbert

    Catbert Banned

    Joined:
    29 Jun 2010
    Messages:
    80
    Likes Received:
    27
    Reputations:
    10
    И любой адекватный человек использует для этих целей другой язык программирования.
    Из-за скорости выполнения и нагрузки он и для работы с сетью с такими "потоками" не особо пригоден.

    Далее рассмотрим кодэ.

    Else - пустое место? Сурово

    Причем нигде не указано, что решение исключительно под win.

    Ты не поверишь, но существует функция array_rand.

    Опять модная функция. Неведомая проверка тоже радует, ТС, специально для тебя у функции file есть специальный флаг FILE_IGNORE_NEW_LINES.

    Бле, пересчет размера массива при каждой итерации...

    А тут в первой функции мы видим пересчет длины статической строки при каждом вызове. Не проще ли было воспользоваться функцией chr (например, chr(mt_rand(0x30, 127)))?
    А во второй функции переменная $str вообще не инициализирована изначально.


    Ни в одной функции нет вообще никакой обработки ошибок. Даже если код где-то навернется, все равно продолжится его выполнение дальше. А навернуться тут очень много шансов.
     
  3. S0meT1me

    S0meT1me Member

    Joined:
    2 Jun 2009
    Messages:
    0
    Likes Received:
    9
    Reputations:
    -5
    А ты загляни в топик продаж - таммного однопоточного софта на ПХП

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

    array_rand возвращает ключ, моя возвращает значение.

    PHP хеширует такие вещи

    Проще с точки зрения скорости выполнения программы, но сложнее с точки зрения её читаемости

    Изначально она и так пуста/нул/ноль.

    Этот код работал уже годика полтора :)

    З.Ы.: Catbert, чего так нервно? давно не трахался?
    З.Ы.2: я не претендую на звание мега-кул программера и знаю свой уровень, если где допускаю ошибку - можно просто сказать, без понтов училки-задротки. и писал этот топик не для того что бы показать какой я крутой задрот, а что бы помочь кому-то
     
    #3 S0meT1me, 19 Sep 2010
    Last edited: 19 Sep 2010
  4. Catbert

    Catbert Banned

    Joined:
    29 Jun 2010
    Messages:
    80
    Likes Received:
    27
    Reputations:
    10
    А в мире много безработных и нищих - это повод на них равняться?

    Правда? Т.е. ты утверждаешь что при работе с сетью пхп покажет скорость аналогичную программе написанной на с++ скажем?

    Т.е. лучше написать mt_rand( 0, count($array) - 1 , чем array_rand($array) ?
    Ну да, конечно, лучше вызвать две функции чем одну.

    $array[mt_rand( 0, count($array) - 1];
    ->
    $array[array_rand($array)];

    В ассоциативный массив заносит штоле?

    И Лада Калина может ездить полтора годика без поломки, однако она ни разу не пример качественного автомобилестроения.
     
    #4 Catbert, 19 Sep 2010
    Last edited: 19 Sep 2010
  5. GRRRL Power

    GRRRL Power Elder - Старейшина

    Joined:
    13 Jul 2010
    Messages:
    823
    Likes Received:
    185
    Reputations:
    84
    Все на пхп и пишут из-за того, что язык прост как зубочистка. А вы своей статьей провоцируете таких горе-кодеров не развиваться, изучая новые языки, а выжимать бесполезные вещи из всё того же php.

    Хеширует? Может быть, кеширует?
    А вообще, я даже проверил это ради интереса. Ничего он там не кеширует.
    PHP:
    <?php
    function microtime_float()
    {
        list(
    $usec$sec) = explode(" "microtime());
        return ((float)
    $usec + (float)$sec);
    }

    $arr = Array();
    for(
    $i=0$i<200000$i++) //заполняем массив побольше
      
    $arr[$i] = mt_rand(1,10);






    $time_start microtime_float();

    for(
    $i=0$i<count($arr); $i++) //Тест 1
      
    $arr[$i] = mt_rand(1,10);

    $time_end microtime_float();
    $time $time_end $time_start;

    print 
    "Test 1: $time<br>";


    $time_start microtime_float();

    for(
    $i=0$cnt count($arr); $i<$cnt$i++) //Тест 2
      
    $arr[$i] = mt_rand(1,10);

    $time_end microtime_float();
    $time $time_end $time_start;

    print 
    "Test 2: $time<br>";
    ?>
    Результаты:
    Code:
    Test 1: 0.170279979706
    Test 2: 0.112259864807
    


    А тут по-моему скорость важнее. А читаемость и так и так нормальна.

    Все же, она не пуста, она неопределена.

    Коды во многих программах работают годика полтора, пока кто-то не находит в них уязвимость и разработчики не начинают паниковать. Ну это так, к слову.
     
    #5 GRRRL Power, 19 Sep 2010
    Last edited: 19 Sep 2010
  6. S0meT1me

    S0meT1me Member

    Joined:
    2 Jun 2009
    Messages:
    0
    Likes Received:
    9
    Reputations:
    -5
    Ох вы и злые... я ж не софт для запуска шатла писал, всё к словам да мелочам придираетесь. Уйду я от вас :)
    Шутка, не дождётесь :)
    Скорость будет сравнима, т.е. отличаться будет не в десятки и сотни раз, а возможно даже и не в разы.
    Catbert, чего ты злой такой? и всё к мелочам приколупываешься?
    Согласен, хотя и тут накодили такие вещи как CakePHP - довольно мощный фреймвёк.
    Ну вот, мы друг-друга поняли :)
    ну в рамках данного скрипта это приблизительно одно и то же, ну а если кодить строго и по канонам то да, ты прав.
     
    2 people like this.