Coder Social home page Coder Social logo

parallcross's Introduction

Подпроцессы на PHP

Задача

Написать класс (семейство классов), позволяющий реализовывать параллельные вычисления на РНР.

Объяснение сути задачи: с помощью данного класса или системы классов становится возможным запускать php скрипты или их части в отдельных процессах. Причём взаимодествие между процессами осуществляется также посредством разработанных классов. При этом под процессом понимается каждый запущеный экземпляр php скрипта.

Обязательные требования:

  • Кроссплатформа. Скрипт должен функционировать как в Windows так и в Unix системах.
  • Должна быть возможность распараллеливать не только скрипт целиком, но и конкретную функцию или метод класса.
  • Скрипт запускающий параллельные процессы должен иметь возможность общаться с ними в обоих направлениях. А именно: отправлять данные в дочерние процессы в любое время, получать данные с любого из дочерних процессов в любое время, определять статус процесса (работает, не работает). Дочерние скрипты также могут отправлять данные в порождающий процесс в произвольное время.
Тестовый пример

Вычисление числа pi с заданной точностью методом Монте-Карло.

Порождающий скрипт index.php запускает несколько дочерних процессов (количество процессов должно быть параметром конфига), каждый из которых начинает вычислять число pi методом Монте-Карло. При запуске параллельного процесса ему передается количество итераций вычислений, определяемое случайным образом. Порождающий скрипт через неравные промежутки времени (определяемые так же случайно) собирает информацию со всех параллельных процессов и выдает совокупный результат (значение числа pi) в браузер с указанием времени, прошедшего с момента запуска главного скрипта.

Реализация системы

Из-за требования кроссплатформы отброшены многие варианты реализации. В итоге использована функция popen() для запуска подпроцесса в фоне и Shared Memory для межпроцессного взаимодействия. Семафоры и мьютексы не задействованы, т.к. согласно манула PHP, они не работают в Windows.

Мыслите абстрактно :) В решении применены следующие понятия:

  • boss - директор. Управляющий процесс. Запуск подпроцессов через него. А так же: синхронизация выборочных/всех, останов выборочных/всех, запрос статуса выборочно/всех. Разница между статусом и синхронизацией: статус просто сообщит, чем занят подпроцесс, на какой он стадии выполнения. Для синхронизации приостанавливаем подпроцесс(ы) до дальшейших распоряжений.
  • worker - воркер. Подпроцесс. Вот их и будем плодить. Воркером может быть метод класса или функция вне класса.
  • dealer -посредник. Любой способ обмена информацией между процессами. Задача посредника - только передавать информацию (строки) между директором и воркерами. Содержание информации его не касается. Сделана реализация через Shared Memory. Так же можно создать класс-посредник на основе Redis (или другого кешера), сокетов, именованных каналов, сессий PHP или записи в файлы без оберток (ооочень медленно будет).

Под управлением одного директора можно запустить воркеров с разными действиями, а так вместе воркеры-методы класса и внеклассовые функции. В приложении можно создать несколько директорских классов со своими настройками под конкретные задачи.

Директор - сигнал, воркер - статус.

Сингалы и статусы перечислены в интерфейсе core\IDealer.

Для каждого подпроцесса создается свой канал обмена сообщениями (посредник). Воркеры не могут общаться друг с другом, только с директором. Директор мониторит все каналы через заданные промежутки времени, воркер проверяет только свой канал так же через промежутки времени.

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

Для воркера есть метод проверки сообщений, для директора - метод управления сообщениями. Оба метода характеризуются двумя параметрами: общее время проверки в секундах (таймаут) и частота обращений к посреднику в течение проверки (NN сообщений в секунду).

Критические ситуации

Решение проходит синтетические тесты, но проблемы будут, когда потребуется написать что-то сложнее "hello, world!".

Проблема №1. Директор может получить данные от воркера сигналом STATUS. Может передать данные с сигналом DATA. Это нормальный запланированный обмен данными. А вот другая ситуация: воркер по своей инициативе передает данные директору. Возможен конфликт.

Сейчас решение такое: при одновременной попытке директора и воркера передать данные считаем данные воркера важнее. Воркер будет игнорировать любые сигналы (скроме STOP и LISTEN), пока его данные не будут приняты. После успешной передачи своих данных воркер переходит в состояние "в ожидании" до получения указаний директора. Правильные реакции на таймауты проверок сообщений зависят от конкретной задачи и ее реализации.

Проблема №2. Допустим, директор запрашивает статус, а воркер проверяет сообщения. При одновременном чтении одного сегмента разделяемой памяти (Shared memory) воркер "глохнет" и не видит сигнала STATUS. На что проверка директора заканчивается по таймауту и объявляет воркера потерянным (STATUS_LOST). Клиентский код директора должен избавляться от таких воркеров, это уход из-под контроля.

Причину этого бага я не нашел. Функции, работающие с Shared Memory, в этом случае ничего не возвращают. Чтение из памяти просто зависает, пока не получится что-то прочитать. Этого зависание длится, пока директор не закончит мониторить посредника и не выйдет с таймаутом. Обходное решение: добавил случайне число в частоту проверки в методе директора. Это не исключает описанную ситуацию, но делает вероятность меньше. Как вариант, придется сменить посредника, т.е. написать его реализацию, не испольуя Shared Memory (не забываем про кроссплатформу).

parallcross's People

Contributors

vijitcoder avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.