Package · thread

Parallel tasks

Run several independent jobs across CPU cores at the same time, then wait for them all. Because processes don’t share memory, results come back through files or a database — not shared variables (see the mental model).

Start many, wait for all

Keep a handle to each Thread, start them, then join() every one:

parallel.php
<?php

require 'vendor/autoload.php';

use Flytachi\Winter\Thread\Thread;

$threads = [];
foreach (range(1, 8) as $reportId) {
  $thread = new Thread(new ReportGenerator($reportId), 'Reports', 'ReportGenerator', "r-{$reportId}");
  $thread->start();
  $threads[] = $thread;
}

// Wait for everyone; count failures by exit code
$failed = 0;
foreach ($threads as $thread) {
  if ($thread->join() !== 0) {
      $failed++;
  }
}

echo "Done. {$failed} failed.\n";

Bound concurrency with a pool

Starting one process per item is fine for a handful of jobs. For hundreds, cap how many run at once so you don’t overwhelm the box:

pool.php
<?php

require 'vendor/autoload.php';

use Flytachi\Winter\Thread\Thread;

$queue         = range(1, 200);
$maxConcurrent = 4;
$running       = [];

while ($queue || $running) {
  // Top up to the concurrency limit
  while (count($running) < $maxConcurrent && $queue) {
      $id = array_shift($queue);
      $thread = new Thread(new ReportGenerator($id), 'Reports', 'ReportGenerator', "r-{$id}");
      $thread->start();
      $running[] = $thread;
  }

  // Reap finished ones
  foreach ($running as $i => $thread) {
      if (!$thread->isAlive()) {
          $thread->join(); // read exit code, free the process
          unset($running[$i]);
      }
  }
  $running = array_values($running);

  usleep(50_000); // 50ms; avoid a busy loop
}

Pick a sane limit

A good starting point is the number of CPU cores for compute-bound work, or higher for I/O-bound work (waiting on the network). Measure — don’t guess.

Collect results

Since children can’t hand objects back, have each task write its result somewhere the parent can read after join():

php
// Inside run(): write a result the parent can pick up
file_put_contents("/tmp/report-{$this->reportId}.json", json_encode($rows));

// In the parent, after join():
$result = json_decode(file_get_contents("/tmp/report-{$reportId}.json"), true);

The exit code from join() is the cheapest result channel of all — use it for plain success/failure and reserve files or a database for real payloads.