PHP+Apache2+Ubuntu Server: как заставить все потоки работать параллельно?

Я обычно работаю с веб-хостинговыми компаниями, но я решил начать изучать работу с серверами, чтобы расширить свои знания.

Я лучше приведу реальный пример, чтобы лучше объяснить мой вопрос:

У меня есть веб-приложение, которое собирает данные из медленного API, который возвращает данные JSON продуктов. У меня есть функция, запускаемая каждый 1:00, выполняющая множество запросов по идентификаторам в моей базе данных.

Crontab:

0 1 * * * cd /var/www/html/tools; php index.php aso Cli_kas kas_alert

Так что это создает процесс для приложения (пожалуйста, исправьте меня здесь, если я ошибаюсь), и каждый процесс создает потоки, и, если быть более точным, они являются многопоточными, поскольку они выполняют больше чем одно: например, извлечение данных из БД, чтобы получить правильные переменные и связать их с запросами API, получить данные из API, организовать их, выполнить поиск соответствующих данных и затем вставить новые данные в базу данных.

Основные функции PHP:

// MAIN: Cron Job Function
public function kas_alert() {


    // 0. Deletes all the saved data from the `data` table 1 month+ ago. 
    // $this->kas_model->clean_old_rows();

    // 1. Get 'prod' table
    $data['table'] = $this->kas_model->prod_table();


    // 2. Go through each row -
    foreach ( $data['table'] as $row ) {

        // 2.2. Gets all vars from the first query.
        $last_row_query = $this->kas_model->get_last_row_of_tag($row->tag_id);
        $last_row       = $last_row_query[0];
        $l_aaa_id       = $last_row->prod_aaa_id;
        $l_and_id       = $last_row->prod_bbb_id;
        $l_r_aaa        = $last_row->dat_data1_aaa;
        $l_r_and        = $last_row->dat_data1_bbb;
        $l_t_aaa        = $last_row->dat_data2_aaa;
        $l_t_and        = $last_row->dat_data2_bbb;
        $tagword        = $last_row->tag_word;
        $tag_id         = $last_row->tag_id;
        $country        = $last_row->kay_country;
        $email          = $last_row->u_email;
        $prod_name      = $last_row->prod_name;
        // For the Weekly report:
        $prod_id        = $last_row->prod_id;
        $today          = date('Y-m-d');

        // 2.3. Run the tagword query again for today on each one of the tags and insert to DB. 
        if ( ($l_aaa_id != 0) || ( !empty($l_aaa_id) ) ) {
            $aaa_data_today   = $this->get_data1_aaa_by_id_and_kw($l_aaa_id, $tagword, $country);
        } else{
            $aaa_data_today['data1']       = 0;
            $aaa_data_today['data2']      = 0;
            $aaa_data_today['data3'] = 0;
        }

        if ( ($l_and_id != 0) || ( !empty($l_and_id) ) ) {
            $bbb_data_today = $this->get_data1_bbb_by_id_and_kw($l_and_id, $tagword, $country);
        } else {
            $bbb_data_today['data1']      = 0;
            $bbb_data_today['data2']    = 0;
            $bbb_data_today['data3'] = 0;
        } 

        // 2.4. Insert the new variables to the "data" table. 
        if ($this->kas_model->insert_new_tag_to_db( $tag_id, $aaa_data_today['data1'], $bbb_data_today['data1'], $aaa_data_today['data2'], $bbb_data_today['data2'], $aaa_data_today['data3'], $bbb_data_today['data3']) ){
        }


        // Kas Alert Outputs ($SEND is echoed in it's original function)
        echo "<h1>prod Name: $prod_id</h1>";
        echo "<h2>tag id: $tag_id</h2>";
        var_dump($aaa_data_today);
        echo "aaa old: ";
        echo $l_r_aaa;
        echo "<br> aaa new: ";
        echo $aaa_data_today['data1']; 

        var_dump($bbb_data_today);
        echo "<br> bbb old: ";
        echo $l_r_and;
        echo "<br> bbb new: ";
        echo $bbb_data_today['data1'];

        // 2.5. Check if there is a need to send something
        $send = $this->check_if_send($l_aaa_id, $l_and_id, $l_r_aaa, $aaa_data_today['data1'], $l_r_and, $bbb_data_today['data1']);

        // 2.6. If there is a trigger, send the email!
        if ($send) {
            $this->send_mail($l_aaa_id, $l_and_id, $aaa_data_today['data1'], $bbb_data_today['data1'], $l_r_aaa, $l_r_and, $tagword, $email, $prod_name);
        }

    }


}

Для @Raptor это функция, которая получает данные API:

// aaa tag Query
// Gets aaa prod dataing by ID. 
public function get_data_aaa_by_id_and_tg($id, $tag, $query_country){

    $tag_for_url = rawurlencode($tag);

    $found = FALSE; 
    $i     = 0;
    $data  = array();       

    // Create a stream for Json. That's how the code knows what to expect to get. 
    $context_opts = array(
        'http' => array(
        'method' => "GET",
        'header' => "Accepts: application/json\r\n"
    ));
    $context = stream_context_create($context_opts); 

    while ($found == FALSE) {

        // aaa Query
        $json_query_aaa = "https://api.example.com:443/aaa/ajax/research_tag?app_id=$id&term=$tag_for_url&page_index=$i&country=$query_country&auth_token=666";
        // Get the Json
        $json_query_aaa = file_get_contents($json_query_aaa, false, $context); 
        // Turn Json to a PHP array
        $json_query_aaa = json_decode($json_query_aaa, true);
        // Get the data2
        $data2      = $json_query_aaa['tag']['data2'];
        if (is_null($data2)){ $data2 = 0; }
        // Get data3
        $data3  = $json_query_aaa['tag']['phone_prod']['data3'];
        if (is_null($data3)){ $data3 = 0; }
        // Finally, the main prod array. 
        $json_query_aaa = $json_query_aaa['tag']['phone_prod']['app_list'];


        if ( count($json_query_aaa) > 2 ) {

            for ( $j=0; $j<count($json_query_aaa); $j++ ) {

                if ( $json_query_aaa[$j]['id'] == $id ) {
                    $found = TRUE;
                    $data  = $json_query_aaa[$j]['data'] + 1;
                    break;
                }

                if ($found == TRUE){
                    break;
                }
            }

            $i++;

        } else {

            $data = 0; 
            break;

        }
    }

    $data['data1']  = $data;
    $data['data2']  = $data2;
    $data['data3']  = $data3;

    return $data;
}

Все потоки накладываются друг на друга, и когда один поток закончен, только тогда - второй поток может продолжить, ect'. И с технической точки зрения, все потоки ждут в ОЗУ, пока тот, который перед ними, не заработает "внутри" ЦП. (поправьте меня, если я снова ошибаюсь:])

Это даже не "щекочет" ОЗУ или ЦП сервера при просмотре его в диспетчере процессов (я использую "htop"). Объем оперативной памяти составляет 400 М /4,25 ГБ, а ЦП - ТОЛЬКО 0,7%-1,3%. Заставить меня почувствовать, что это не лучшее, что я могу получить от моего текущего сервера, и получить медленные результаты от моего веб-приложения.

Как сделать так, чтобы все потоки работали параллельно, но не до такой степени, что мое приложение зависало из-за нехватки ЦП или ОЗУ?

0 ответов

Другие вопросы по тегам