За последние 24 часа нас посетили 47544 программиста и 1806 роботов. Сейчас ищут 1103 программиста ...

Параллельное выполнение скриптов.

Тема в разделе "PHP для новичков", создана пользователем Sergey_k6, 28 май 2022.

  1. iceblood

    iceblood Активный пользователь

    С нами с:
    20 фев 2020
    Сообщения:
    83
    Симпатии:
    12
    Дело в том что mssql или (я использовал) mariadb, на шаге вызова parent->child одинаково афектят. Мы видим что при вызове parent->child простой код в child вроде
    Код (Text):
    1. echo "hi am child"
    отрабатывает пока дело не доходит до подключений к серверу БД (Это отличный кейс для факультатива).
    В patent_exec.php можно сколько угодно вызвать разных скриптов которые выполнят свой код child.php child2.php ...
    Каждый child по выполнении работы просто фиксирует результат в таблицу которую нужно создать.
    Код (Text):
    1. create table log_child(
    2.     id int not null auto_increment,
    3.     child_name text,
    4.     create_date datetime,
    5.     src_data text,
    6.     out_data text,
    7.     status bool default false,
    8.  
    9. );
    child можно научить представляться для записи в в поле child_name text
    PHP:
    1. include 'config.php';
    2. echo "\nhi am child: " .$argv[0]."\n"; // вывести себя
    3. $query = 'select 22';
    4.  
    5. echo "dbname: ".$dbname."\n";
    6. $link = mysqli_connect(    $server,    $username,    $password,    $dbname, );
    7. $result = mysqli_query($link, $query);
    8. while ($row = mysqli_fetch_row($result)) {
    9.     echo("result: ".$row[0]);
    10. }
    Код (Text):
    1. D:\tmp\forum\parrallel>php parent_exec.php
    2. Cannot load Xdebug - it was already loaded
    3. Cannot load Xdebug - it was already loaded
    4.  
    5. hi am child: D:\tmp\forum\parrallel\child.php //child
    6. dbname: tt
    7. result: 22Cannot load Xdebug - it was already loaded
    8.  
    9. hi am child: D:\tmp\forum\parrallel\child2.php //child2
    10. dbname: tt
    11. result: 22
    Точно нет.
     
    inkom нравится это.
  2. iceblood

    iceblood Активный пользователь

    С нами с:
    20 фев 2020
    Сообщения:
    83
    Симпатии:
    12
    Покопался, и как предполагал когда parent->child вызывает, теряются переменные окружения. При импорте переменных окружения в child, скрипт с базой нормально работает. Я для теста сделал топорно ) Подключил фаил с массивом переменных в child и в цыкле их импортул
     
    #27 iceblood, 2 июн 2022
    Последнее редактирование: 2 июн 2022
    inkom нравится это.
  3. Sergey_k6

    Sergey_k6 Новичок

    С нами с:
    28 май 2022
    Сообщения:
    32
    Симпатии:
    0
    Добрый день.
    И так по поводу передачи переменных и работы процессов разобрались, проблема с переменным окружения решилась
    Теперь вопрос, так как всё делаю в первые, подскажите пожалуйста как писать вывод в поток stdout

    PHP:
    1. $fh_stdout = fopen('php://stdout','w');
    2. // Открыли
    3. fwrite($fh_stdout,base64_encode($contents));
    4. // записали
    5. // Как ещё до записать данные в конец уже записанных в этом потоке?
    6. if(is_resource($fh_stdout)) fclose($fh_stdout);
    7. Закрыли.
    Кто-нибудь может подсказать?
     
  4. Sergey_k6

    Sergey_k6 Новичок

    С нами с:
    28 май 2022
    Сообщения:
    32
    Симпатии:
    0
    Добрый день.
    После некого отсутствия предлагаю продолжить тему.

    В общем с проблемами непонятных ошибок я разобрался, нужно передавать в вызов переменные окружения, так как мы не в режиме CGI и поэтому процесс запускается в вакууме. Сейчас всё заработало.

    Осталось решить последний момент, вывод результата в поток stdout
    Опять же я чайник в этом процессе. Помогите кто знает.
    PHP:
    1. // Указатель на поток вывода
    2. $fh_stdout = fopen('php://stdout','w');
    3. // Запись в поток вывода
    4. fwrite($fh_stdout,base64_encode($contents));
    5. // ВОПРОС: Как до записать в конец уже ранее записанных данных при предыдущем вызове fwrite()
    6.  
    7. Закрытие потока на стороне Child
    8. if(is_resource($fh_stdout)) fclose($fh_stdout);
    9. После чего должно proc_get_status()['running'] стать != 1
    Заранее благодарю за помощь
    --- Добавлено ---
    Вообще я не совсем понимаю что можно передавать в поток что нельзя, и как этот поток работает.
     
  5. iceblood

    iceblood Активный пользователь

    С нами с:
    20 фев 2020
    Сообщения:
    83
    Симпатии:
    12
    https://www.php.net/manual/ru/function.fopen.php
    'a+' Открывает файл для чтения и записи; помещает указатель в конец файла. Если файл не существует - пытается его создать. В данном режиме функция fseek() влияет только на позицию чтения, записи всегда добавляются в конец.
     
  6. Sergey_k6

    Sergey_k6 Новичок

    С нами с:
    28 май 2022
    Сообщения:
    32
    Симпатии:
    0
    Добрый день, iceblood спасибо огромное что помогаете.
    В общем теперь следующий кирпичь, это размер pipe в windows, знающие люди уже говорили, что это костыль, но я как-то не послушал, решил проверить. Действительно Proc_open мне обкладывает 3я pipeами после открытия процесса и на этом всё завершается.
    Я думал, что со стороны стандартных средств php будет механизм контроля переполнения и мне не придётся его изобретать самому, так как это сложно. Да и время на выполнение данного изыскания меня уже закончилось.
    Поэтому прошу уже помощи на коммерческой основе.
    Кто может взять и за сколько на написание PHP кода:

    Организация передачи данным между параллельными процессами с помощью Socketа.
    Socket открываетродитель.

    // Открытиесокета
    PHP:
    1. $socket_read = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);

    PHP:
    1. // Привязываем его к указанным ip и порту
    2. $port=8000;
    3. $soc_IP="127.0.0.1";
    4. while(!socket_bind($socket_read,$soc_IP,8000) && $port<=9000) {$port++;};
    5. echo "\$port=8000 => ".$port."\n";
    Вопрос: такой конструкции достаточно чтобы понять, что порт занять и подобрать другой для корректного открытия?

    PHP:
    1. // Разрешаем использовать один порт для нескольких соединений
    2. socket_set_option($socket_read, SOL_SOCKET, SO_REUSEADDR, 1);
    3. // Слушаемсокет
    4. socket_listen($socket_read);
    К этому Socketу в произвольном порядке, после выполнения, в зависимости кто успел первым, подключаются Child скрипты и кладут в него номер [IDChild] и данные [serialize(array())].

    !!! Процессы отрыты в родителе с помощью proc_open, и их данные на стороне родителя сохранены в массив, по которому производиться опрос выполнения результатов.

    !!! Вопрос socketу всё равно в какой кодировке передаются данные и на него не могут влиять всякие спец символы? Или же всё равно данные надо оборачивать в base64_decode (base64_encode())?


    Далее:
    Если к Socketу уже подключён какой-нибудь Childто, Child, который пытается положить данные, должен ждать пока Socketне освободится для приёмки данных.


    Далее:
    Родитель слушает Socket и читает из него данные по [IDChild] (номер процесса по массиву), заносит в массив данные который он прочитал.


    Далее:
    Родитель очищает Socket.


    Далее:
    Ожидающий(ие) Childкак только видят, что Socket пустой, по принципу: кто успел того и тапки, записывают в Socket свои данные, Child кто не успел ждут с помощью usleep(в миллисекундах и снова пытаются проверить свободность Socket)


    Далее: Количество открытых процессов произвольно, но всё-таки посчитано в Родителе, тем самым получив Nраз в socket данные от Childов и расставив их по массиву вы выходим из процесса и закрываем socket_close($socket_read);


    Задача организовать передачу данных по описанному выше принципу.
    Рассказать в виде удалённого консультатива как это работает.
    На выходе в Родителе после заверения чтения данных от Child мне нужны [ID] и ассотиативный Array [key]=>[val]


    Среда:
    Apache/2.4.10 (Win32)
    Php 5.6.1
    Windows NT WIN7HOMES 6.1 build 7601 (Windows 7 Ultimate Edition Service Pack 1) i586

    Глобальные ограничения!
    - Модуль CGI (запускать нельзя сервер не наш)
    – общие переменные среды будут недоступны
    - В этой среде Pipe как объект имеет ограничение до 4096 байт
    Превышение этого лимита приводит к proc_get_status($res)['running'] всегда висит 1 что логично так как Child просто не смог дописать в него своё закрытие.
    - Stomp тоже не вариант, так как windowsне может выполнить shmop_delete($shmop); shmop_close($shmop); так как https://stackoverflow.com/questions/12378098/php-delete-shared-memory-on-windows сервер не наш! Ломать и перепрописывать процессы, чтобы сработал shmop_close я не могу (да и ни разу не пробовал это в windowsкостыль!)
     
  7. iceblood

    iceblood Активный пользователь

    С нами с:
    20 фев 2020
    Сообщения:
    83
    Симпатии:
    12
    Мне, как то помог совет - взять тетрадку и нарисовать схему как я хочу, что бы задуманное мною работало и как это (можно доп. схему) должно быть. Графическая схема - наглядна и позволяет избавиться от не определенности. Я ранее предлагал, использовать промежуточное решение с таблицей. Представив вашу схему было бы думаю не сложно найти простое решение.