Как из внутреннего класса потока обратиться к глобальным переменным самого скрипта?

Bars

Новичок
Делаю очень ресурсоёмкий парсер сайта, который иногда даже ложит сервер, и понадобилось вникнуть в потоки:
http://masnun.com/2013/12/15/multithreading-in-php-doing-it-right.html

В моём скрипте есть класс WorkerThreads:

PHP:
    $parsed = 0;

    class WorkerThreads extends Thread {
        private $data;
    
        public function __construct($response) {
            $this->data = $response;
        }
    
        public function run() {
            global $parsed;
            echo '['.$parsed.'] ';
            // Ресурсоемкая задача с кучей foreach'ев над большими массивами
        }
    }
И есть глобальная переменная $parsed ВНЕ этого класса, в которую надо записать значение из этого класса (потока) (да хоть прочитать, а то выводится лишь "[] [] [] [] [] [] [] [] "). А таких переменных несколько! Плюс запись всех их в JSON

Что делать в таком случае?
 
Последнее редактирование:

Bars

Новичок
Даже попробовал передать все глобальные переменные в конструктор класса и хранить их там.
PS: Но это овер-костыльно и может сделать только хуже

PHP:
class WorkerThreads extends Thread {
    private $data;
    static $iters = -1;
    static $locat = '';
    static $categ = '';
    static $sename = '';
    static $sessi;
    static $gpage = 1;
    static $pgs = -1;
    static $rgs;
    static $parsed = 0;

    public function __construct($response, $ccou, $loc, $cate, $sname, $ses, $gpg, $pags, $lst) {
        $this->data = $response;
        if ($ccou > -1) WorkerThreads::iters = $ccou; // Parse error: syntax error, unexpected '=' on this line
        if (WorkerThreads::locat == '') WorkerThreads::locat = $loc;
        if (WorkerThreads::categ == '') WorkerThreads::categ = $cate;
        if (WorkerThreads::sename == '') WorkerThreads::sename = $sname;
        if (!isset(WorkerThreads::sessi)) WorkerThreads::sessi = $ses;
        if ($gpg > WorkerThreads::gpage) WorkerThreads::gpage = $gpg;
        if (!isset(WorkerThreads::rgs)) WorkerThreads::rgs = $lst;
        if ($pags > -1) WorkerThreads::pgs = $pags;
    }

    public function run() { ... }
}
Однако получаю ошибку
Parse error: syntax error, unexpected '=' in parser.php on line 15
Я уже отчаялся и написал вопрос сюда. У меня испытательный срок идет, а я вникаю в потоки и не могу получить переменные уже третий день подряд.
 
Последнее редактирование:

c0dex

web.dev 2002-...
Команда форума
Партнер клуба
@Bars, WorkerThreads::iters >> WorkerThreads::$iters если уж на то пошло.
 

Bars

Новичок
Неужели нет способа сделать всё по первому варианту?
 

Bars

Новичок
Всё-таки второй провалился. Перезаписывается JSON. Ведь его надо перезаписывать уже после итерации всех потоков. #2 провал
 

antson

Новичок
Партнер клуба
вот точно тебе нужно менять глобальную переменную из потока ?

идеологически правильнее
большая задача разбита на N частей
запускаем дочерние потоки
пока не завершены все потоки
ждем окончания любого из них.
получаем от потока ответ (ид_части, результат)
тупо например заносим как $otvet[ид_части]=результат;
кцикл

собрать результирущий ответ из частей.
продолжит выполнение дальше
 
  • Like
Реакции: Bars

antson

Новичок
Партнер клуба
@Bars, штатными средствами http://php.net/manual/en/threaded.synchronized.php
в примере возращается указатель на объект класса My
простое решение ввести в классе нужные тебе публичные проперти
ну или красиво , то приватные и метод получения их значений.
 
  • Like
Реакции: Bars

Bars

Новичок
@Bars, штатными средствами http://php.net/manual/en/threaded.synchronized.php
в примере возращается указатель на объект класса My
простое решение ввести в классе нужные тебе публичные проперти
ну или красиво , то приватные и метод получения их значений.
Уже начинаю что-то понимать, но не полностью. Например я могу сделать так:
PHP:
                        $data = curl_multi_getcontent($info['handle']);
                        $workers[$co_unt] = new WorkerThreads($data);
                        $workers[$co_unt]->start();
                        $workers[$co_unt]->result_answer; // Тем самым получив из одного из потоков переменную $result_answer, с которой сможем теперь работать и брать результат выполнения из неё
                        ++$co_unt;
Но надо ведь как-то подождать пока поток выполнится и запишет её, ведь иначе
PHP:
$workers[$co_unt]->result_answer;
Выдаст мне null, а не записанный ответ
 

Bars

Новичок
Скрипт либо виснет на бесконечность времени (F5 спасает), либо ничего не выводит
PHP:
$answer = array();
class WorkerThreads extends Thread {
    public $data;

    public function __construct($response) {
        $this->data = $response;
    }

    public function run() {
        $this->synchronized(function($thread){
            if (!$thread->done)
                $thread->wait();
        }, $this);
    }
}

$co_unt = 0;
while (perebor_dannyh) {
                        $data = curl_multi_getcontent($info['handle']);
                        $workers[$co_unt] = new WorkerThreads($data);
                        $workers[$co_unt]->start();
                        $workers[$co_unt]->synchronized(function($thread){
                          $answer[0] = $thread->data; // Пытаюсь достать из потока переменную $data и записать в $answer, тщетно. Или как надо?
                          $thread->notify();
                        }, $workers[$co_unt]);
                        //$workers[$co_unt]->join();
                        ++$co_unt;
}

foreach ($workers as $wrk) $wrk->join();
foreach ($answer as $ans) echo "[$ans] <br />"; // Ничего не возвращает.
@antson
 
Последнее редактирование:

Bars

Новичок
неправильно ты, дядя фёдор, бутерброд ешь. лучше почитай о мультикурл http://php.net/manual/en/function.curl-multi-exec.php
Я и мультикурл использую. Просто полученные от него данные требуют серьёзной обработки. Поэтому у меня два вида многопоточности: непосредственно для cURL (curl_multi), и для множественных переборов больших массивов (pthreads). Не получается второй
 

antson

Новичок
Партнер клуба
@Bars, освой сперва мультипоточность.
для примера возьми простейшую задачу нужно числа от 1 до 10 перемножить на 2.
разберись кто должен множить.
кто раздавать числа в работу.
где собирать результат.
 

Bars

Новичок
Вроде разобрался, ведь оно работает...
Но работает еще дольше, чем вообще без использования потоков.
И ЕЩЕ вдвое дольше, если использовать вроде бы нужный $worker->join();
PHP:
<?php
class WorkerThreads extends Thread {
    private $data;
    private $result = '';
    private $locs_list;
    private $keys_list;
    public  $finished = false;

    public function __construct($response, $loc_s, $key_s) {
        $this->data = $response;
        $this->locs_list = $loc_s;
        $this->keys_list = $key_s;
    }

    public function run() {
        $this->synchronized(function($thread){
            // Ресурсоемкая задача
            $this->finished = true;
        }, $this);
    }

    public function getResult() { return $this->result; }
}

$worker = new WorkerThreads($data, $list, $keys);
$worker->start();
$worker->synchronized(function($thread){
    global $sess;
    global $parsed;
    if ($thread->finished) {
        $com_t = $thread->getResult();
        if ($com_t != '') {
            if (!array_key_exists($com_t, $sess['keys'])) $sess['keys'][$com_t] = 1;
            else ++$sess['keys'][$com_t];
            ++$parsed;
        }
    } else $thread->wait();
    usleep(50000);
    $thread->notify();
}, $worker);
//$worker->join();
?>
@antson
 
Последнее редактирование:

AmdY

Пью пиво
Команда форума
А с чего ты взял, что в несколько потоков будет быстрее если твой сервак падает даже в один поток?
Ты мультикурлом достаёшь данные в несколько потоков, т.к. сеть медленная. Дальше эти данные складываешь куда-нибудь. Отдельно запускаешь скрипт или несколько, который разгребает эту очередь. Здесь ключевое слово - очередь, она позволяет тебе регулировать нагрузку и распределять задачи между воркерами. А Thread - это на 99% костыль.
 
  • Like
Реакции: Bars

antson

Новичок
Партнер клуба
@Capital, ну я тоже старичок. И застал еще времена когда у функций не было параметров.
Это я к тому, что область видимости переменных замечательная вещь. А вот ситуация когда из-за кривых рук новичка,
который залез не туда в глобальной видимости и все рухнуло более вероятна.
 

antson

Новичок
Партнер клуба
@Capital, вопрос зачем реально в пхп нужна многопоточность ? пока мне попадались всего два случая.
1) парсеры сайтов
2) попытка через нее решить проблемы своей криворукости. ф1 + ф2 + ф3 считается долго. давайте вместо того чтобы исправить запустим их все сразу.
 
Сверху