PHP Classes

How to Implement PHP Parallel Processing Using JavaScript Start Multiple PHP Tasks On the Server Using the Package MultiOne: Execute many tasks in parallel using JavaScript

Recommend this page to a friend!
  Info   Example   Screenshots   View files Files   Install with Composer Install with Composer   Download Download   Reputation   Support forum   Blog    
Last Updated Ratings Unique User Downloads Download Rankings
2025-01-08 (8 days ago) RSS 2.0 feedNot enough user ratingsTotal: 13 This week: 9All time: 11,459 This week: 6Up
Version License PHP version Categories
multione 1.0.0GNU Lesser Genera...7HTTP, Language, Performance and optim..., P...
Description 

Author

This package can execute many tasks in parallel using JavaScript.

It can generate a Web page interface containing JavaScript code that sends HTTP requests to the Web server to execute multiple tasks in parallel.

The package can process the HTTP requests sent from the browser using JavaScript and invoke given callback functions in PHP that return values sent to the browser as HTTP request responses.

Picture of Jorge Castro
  Performance   Level  
Name: Jorge Castro <contact>
Classes: 34 packages by
Country: Chile Chile
Age: 48
All time rank: 12333 in Chile Chile
Week rank: 4 Up1 in Chile Chile Up
Innovation award
Innovation award
Nominee: 14x

Winner: 2x

Example

<?php /** @noinspection PhpUnhandledExceptionInspection */

/** @noinspection PhpUnusedParameterInspection */

use Eftec\MultiOne\MultiOne;

include
__DIR__ . '/../vendor/autoload.php';
MultiOne::Factory(
   
1000, // every miliseconds
   
basename(__FILE__), // the url to call
)->setMethods(
    static function(
$numWorkers): array { // the initial call
       
echo "<h1>Example 1 " . MultiOne::VERSION . "</h1>";
        echo
"This example draws a screen then it calls 4 workers every 4 second.<br>";
        echo
"Every worker do some job. Once all workers is done, then it executed the worker-end<br>";
        echo
"starting..";
       
MultiOne::setData(40);
       
// it creates the initial payload for every worker.
       
return array_fill(0, $numWorkers , 'initialpayload');
    },
    static function(
$idWorker, $payload): array { // the worker call
        // it reads the data and reduces to 1.
       
$workPending = MultiOne::getSetDataSafe(static function($old) {
            return
$old - 1;
        });
        if (
$workPending <= 0) {
            return
MultiOne::msgAnswer('end','done','done');
        }
       
usleep(random_int(500, 1500));
        return
MultiOne::msgAnswer('run',$workPending,"Worker: $idWorker, time:" . time() . " pending: " . $workPending);
    },
    static function(
$bodies) { // the worker-end call
       
echo "all worker ended";
    }
)->
setJSMethods(
   
"function(nw,json) {
    console.log(json);
    return json;
    }"
,
   
"function(nw,response) {
    return response;
    }"
)
    ->
setUI()->runAuto();




Details

MultiOne

MultiOne is a library to execute concurrent tasks programmed in PHP using JavaScript.

This library is focused to run local task easily and without much extra boilerplate.

The goal is to be able to run CPU intensive tasks using multiples cores by distributing every task in different workers (what does the job). It also adds a new functionality, it allows to simulate a Command Line Interface (CLI) using the web.

Packagist Total Downloads [Maintenance]() [composer]() [php]() [php]()

docs/img5.png

<!-- TOC --> * MultiOne * How to use it? * Logic * How to synchronize and share information between every worker? * Command Line Interface (CLI)

* Example

* Example of multi operations * Changelog <!-- TOC -->

How to use it?

Install this library using Composer

composer require eftec/multione

And call it as follows:

use Eftec\MultiOne\MultiOne;
include __DIR__ . '/../vendor/autoload.php';
$multiOne = MultiOne::Factory(
    1000, // every miliseconds
    basename(__FILE__), // the url to call
    4 // the number of workers
)->setMethod(
    static function($numWorkers):array { // the initial call
        // todo code
        $result=[];
        for($instance=0; $instance<$numWorkers; $instance++) {
            $result[$instance]='initial';
        }
        return $result;
    },
    static function($idWorker, $body):array { // the worker call                
        // some job here
        if($done){
            return ['type'=>'end','result'=>'done','ui'=>'done'];
        }       
        return ['result'=>'working', 'ui'=>"Worker: $idWorker"];
    },
    static function($bodies) { // the worker-end call
        echo "all workers ended";
    }
)->setHtmls(
    '<div id="PREFIX_contentcontent">%s</div>', // how the content is draw
    '<div id="PREFIX_worker_%s"></div><div id="PREFIX_worker_error_%s"></div>', // how every worker is draw
    '<div id="PREFIX_worker_end"></div>', // how the worker-end is draw.
    "loading ?" // the loading ui. If empty, then it don't use loading ui
)->runAuto();

The browser will show the next screen docs/img1.png

> In the folder examples you can find examples of code.

Logic

There are 3 functions (defined by setMethod) that are called in different stages of the process

setMethod(
    static function($numWorkers):array { 
      // the initial call (returns an array with all the payload for each worker)    
    },
    static function($idWorker, $body):array { 
      // the worker call                       
    },
    static function($bodies) { 
      // the worker-end call, it returns a message.       
    }

  • The initial function is called at the beginner of the operation. * It must create the initial payload, it also display the UI and it could show some visual content. * After the initial function is called, then JavaScript (in the HTML) does the rest of operation and coordination.
  • Every "n" milliseconds, every worker is called (unless it is in use). Each worker receives the load of its worker. * Once the worker is done, it must return the next structure: type* the type of result, example: "end" or "run". * If a worker returns end, the the worker will stop its operation. * If none is set then it uses "run". resultthe result (load) of the worker. If none is set, then it uses theui* (if any) or empty uithe visual result of the worker. If none is set, then it usesresult*
  • When all workers are finished, then worker_end is executed. * It receives the load of all workers and it results a visual text.

docs/img2.png

How to synchronize and share information between every worker?

You can use the payload to synchronize the operations of every worker.

docs/img3.png

However, if it is not enough, then you can use the next alternatives:

  • You can use an external library such as eftec/cacheone, to share information between workers
  • You can use APCU, Redis, Memcache, database or file system
  • The library contains 3 methods to save file locally MultiOne::getGetData* to get some data using a local file MultiOne::getSetData* to set some data using a local file MultiOne::getSetDataSafe* to get some data, replace the value, and save in a safe way

docs/img4.png

Command Line Interface (CLI)

It is possible to run the library to display a command line interface on web.

docs/imgcli.png

In CLI mode, the code calls a single worker only when the user inputs a value in the input text.

Example

MultiOne::Factory(
    1000, // every miliseconds
    basename(__FILE__), // the url to call
)->setMethods(
    static function($numWorkers, $payload): array { // the initial call
        $_SESSION['USERNAME'] = 'admin';
        return ["Start"], // the initial screen
];
    },
    static function($idWorker, $payload): array { // the worker call
        // it reads the data and reduces to 1.
        $username=$_SESSION['USERNAME']??null;
        if($username===null) {
            throw new RuntimeException('no user is not set');
        }
        return MultiOne::msgRun("$username:{$payload['line']}","@$username> ");
    }
)
    ->setCli('> ','100%','600px') // we use a cli
    ->runAuto();

Where:

MultiOne::msgAnswer('run','text to add to the console','a prompt'); // run,full,error

> The text to display could contains colors. Example:

MultiOne::msgAnswer('run','<red>red text</red><byellow>yellow background</byellow>');

Example of multi operations

You can find this example in the example folder

Lets say we need to execute 100 operations in 4 workers

First, we create the 4 workers

MultiOne::Factory(
    1000, // every miliseconds
    basename(__FILE__), // the url to call
    4     // the number of workers
)

Then, we create the initial load and we split in 4 workers

static function($numWorkers):array { // the initial call
    $result=[];
    $numOper=100;
    $split=ceil($numOper/$numWorkers);
    for($instance=0; $instance<$numWorkers; $instance++) {
        $result[$instance]=['done'=>$split*$instance,'task'=>[
          'init'=>($split*$instance)+$split,
          'end'=>$split*$instance]
          ];
    }
    return $result;
}

Then, every worker must do the job

static function($idWorker, $body):array { // the worker call
    $body['done'] += 1;
    if($body['done']>=$body['task']['end']) {
        $body['done']='ok';
        return MultiOne::msgAnswer('end',$body,'done');
    }
    usleep(random_int(500, 1500));
    MultiOne::msgAnswer('run',$body,"Worker: $idWorker");
}

// And when all jobs are done, we could close it. It could be used to merge all the results. It only needs to return a visual result.

static function($body) { // the worker-end call
    echo "all workers ended";
}

Optionally we could do changes in the UI.

Finally, our code could look as follows:

MultiOne::Factory(
    1000, // every miliseconds
    basename(__FILE__), // the url to call
    4     // the number of workers
)->setMethods(
    static function($numWorkers):array { // the initial call
        $result=[];
        $numOper=100;
        $split=ceil($numOper/$numWorkers);
        for($instance=0; $instance<$numWorkers; $instance++) {
          $result[$instance]=['done'=>$split*$instance,'task'=>[
            'init'=>($split*$instance)+$split,
            'end'=>$split*$instance]
            ];
        }
        return $result;
    },
    static function($idWorker,$body):array { // the worker call
        $body['done'] += 1;
        if($body['done']>=$body['task']['end']) {
            $body['done']='ok';
            return MultiOne::msgAnswer('end',$body,'done');
        }
        usleep(random_int(500, 1500));

        return MultiOne::msgAnswer('run',$body,"#$idWorker {$body['done']}");
    },
    static function($body) { // the worker-end call
        echo "all worker ended";
    }
)->runAuto();

Changelog

  • 1.3 2025-01-04 * Added CLI * Added sessions. By default it uses sessions.
  • 1.2 2025-01-02 * Fixed a problem with PHP 8.4
  • 1.1 2024-12-27 * fixed a small bug in initialize some arguments * fixed a bug with some examples.
  • 1.0 2024-12-27 * first version

Screenshots (6)  
  • docs/img1.png
  • docs/img2.png
  • docs/img3.png
  • docs/img4.png
  • docs/img5.png
  • docs/imgcli.png
  Files folder image Files (19)  
File Role Description
Files folder imageexamples (8 files)
Files folder imagesrc (1 file, 1 directory)
Accessible without login Plain text file composer.json Data Auxiliary data
Accessible without login Plain text file README.md Doc. Documentation

  Files folder image Files (19)  /  examples  
File Role Description
  Accessible without login Plain text file example1.php Example Example script
  Accessible without login Plain text file example2.php Example Example script
  Accessible without login Plain text file example2_error.php Example Example script
  Accessible without login Plain text file example3.php Example Example script
  Accessible without login Plain text file examplecli.php Example Example script
  Accessible without login Plain text file examplecli_simple1.php Example Example script
  Accessible without login Plain text file example_simple1.php Example Example script
  Accessible without login Plain text file example_simple2.php Example Example script

  Files folder image Files (19)  /  src  
File Role Description
Files folder imagetemplates (2 files)
  Plain text file MultiOne.php Class Class source

  Files folder image Files (19)  /  src  /  templates  
File Role Description
  Accessible without login Plain text file template_cli.php Aux. Configuration script
  Accessible without login Plain text file template_multi.php Aux. Configuration script

The PHP Classes site has supported package installation using the Composer tool since 2013, as you may verify by reading this instructions page.
Install with Composer Install with Composer
 Version Control Unique User Downloads Download Rankings  
 100%
Total:13
This week:9
All time:11,459
This week:6Up