Пакет · thread

Параллельные задачи

Запускайте несколько независимых задач одновременно на разных ядрах CPU, затем дождитесь их всех. Поскольку процессы не делят память, результаты возвращаются через файлы или базу данных, а не через общие переменные (см. модель работы).

Запустить много, дождаться всех

Сохраните ссылку на каждый Thread, запустите их, затем вызовите join() для каждого:

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;
}

// Дожидаемся всех; считаем неудачи по коду выхода
$failed = 0;
foreach ($threads as $thread) {
  if ($thread->join() !== 0) {
      $failed++;
  }
}

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

Ограничьте параллелизм пулом

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

pool.php
<?php

require 'vendor/autoload.php';

use Flytachi\Winter\Thread\Thread;

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

while ($queue || $running) {
  // Добираем до лимита параллелизма
  while (count($running) < $maxConcurrent && $queue) {
      $id = array_shift($queue);
      $thread = new Thread(new ReportGenerator($id), 'Reports', 'ReportGenerator', "r-{$id}");
      $thread->start();
      $running[] = $thread;
  }

  // Убираем завершившиеся
  foreach ($running as $i => $thread) {
      if (!$thread->isAlive()) {
          $thread->join(); // читаем код выхода, освобождаем процесс
          unset($running[$i]);
      }
  }
  $running = array_values($running);

  usleep(50_000); // 50 мс; избегаем busy-loop
}

Выберите разумный лимит

Хорошая отправная точка — число ядер CPU для вычислительных задач или больше для I/O-задач (ожидание сети). Измеряйте, а не гадайте.

Собирайте результаты

Поскольку дочерние процессы не могут вернуть объекты, пусть каждая задача пишет свой результат туда, откуда родитель прочитает его после join():

php
// Внутри run(): пишем результат, который заберёт родитель
file_put_contents("/tmp/report-{$this->reportId}.json", json_encode($rows));

// В родителе, после join():
$result = json_decode(file_get_contents("/tmp/report-{$reportId}.json"), true);

Код выхода из join() — самый дешёвый канал результата: используйте его для простого «успех/неудача», а файлы или базу данных приберегите для настоящих payload’ов.

Связанное