Allows running the tasks in multiple threads using pthreads PHP extension

v1.0.0 2019-02-28 16:46 UTC

This package is not auto-updated.

Last update: 2021-12-04 05:04:18 UTC


README

This package is a wrapper for pthreads extension. And provides a simplified way to run tasks in multiple threads and collect the results.

Requirements

The only requirement is to have installed and enabled the latest (v3) version of pthreads PHP extension. Please check its requirements here.

Installation

  1. Require the package:
     composer require contextualcode/threads
    
  2. Done! Now you can define custom tasks. The should extend ContextualCode\Threads\Thread class and should implement do method. Please use ContextualCode\Threads\Runner to run them.

Usage

Lets say, we have a simple task: generate random number and sleep for 1 second. And we want to build Symfony 4 Command, which will run that task 10 times, using 10 concurrent threads.

  1. First of all we need to define the task class in src/Task.php:

     <?php
        
     namespace App;
        
     use ContextualCode\Threads\Thread;
        
     class Task extends Thread
     {
         public function do()
         {
             $number = rand(0, 1000);
             sleep(1);
             return $number;
         }
     }
    
  2. Now we need to create a src/Commond/TestThreadsCommand.php which will run Task using 10 threads:

     <?php
        
     namespace App\Command;
        
     use Symfony\Component\Console\Command\Command;
     use Symfony\Component\Console\Input\InputInterface;
     use Symfony\Component\Console\Output\OutputInterface;
     use Symfony\Component\Debug\ErrorHandler;
        
     use App\Task;
     use ContextualCode\Threads\Runner;
        
     class TestThreadsCommand extends Command
     {
         protected static $defaultName = 'app:test-threads';
        
         protected function configure()
         {
             $this->setDescription('Tests contextualcode/threads package');
         }
        
         protected function execute(InputInterface $input, OutputInterface $output)
         {    
             $concurrentThreadsNumber = 10;
             $timeToRunTask = 10;
        
             // Run the tasks
             $start = microtime(true);
             $runner = new Runner($concurrentThreadsNumber);
             for ($i = 1; $i <= $timeToRunTask; $i++) {
                 $runner->addTask(new Task());
             }
             $numbers = $runner->process();
        
             // Output results
             $runtime = microtime(true) - $start;
             $avg = array_sum($numbers) / count($numbers);
             $output->writeln('Random numbers: ' . implode(', ', $numbers));
             $output->writeln('Average number: ' . number_format($avg, 2));
             $output->writeln('Execution time: ' . number_format($runtime, 2));
         }
     }
    
  3. And run the command:
     $ php bin/console app:test-threads
     Random numbers: 916, 98, 219, 999, 323, 205, 259, 979, 328, 871
     Average number: 519.70
     Execution time: 1.13
    
  4. If you will get Serialization of 'Closure' is not allowed error during the command run. It might be because of this bug. Just add the following code at the top of execute method of TestThreadsCommand command. So it will look like:
     protected function execute(InputInterface $input, OutputInterface $output)
     {
         if ($phpHandler = set_exception_handler(function() {})) {
             restore_exception_handler();
             if (is_array($phpHandler) && $phpHandler[0] instanceof ErrorHandler) {
                 $phpHandler[0]->setExceptionHandler(null);
             }
         }
        ...
     }