Frage

EDIT: Ich habe dieses C in der Hoffnung, mit Tags versehen habe mehr Antwort zu erhalten. Es ist mehr die Theorie, die ich interessiert bin als eine bestimmte Sprache Umsetzung. Wenn Sie also ein C-Coder sind Sie in der folgenden PHP als Pseudo-Code behandeln und fühlen sich frei, mit einer Antwort in C geschrieben reagieren zu können.

Ich versuche, einen PHP CLI Skript zu beschleunigen, indem sie ihre Aufgaben parallel ausführen statt seriell. Die Aufgaben sind völlig unabhängig voneinander, so dass es keine Rolle spielt, welche Reihenfolge sie Start / Ziel in.

Hier ist das Original-Skript (beachten Sie alle diese Beispiele sind abgespeckte zurück zur Klarheit):

<?php

$items = range(0, 100);

function do_stuff_with($item) { echo "$item\n"; }

foreach ($items as $item) {
    do_stuff_with($item);
}

Ich habe es geschafft, um es auf dem $items parallel funktioniert mit pcntl_fork() wie unten dargestellt:

<?php

ini_set('max_execution_time', 0); 
ini_set('max_input_time', 0); 
set_time_limit(0);

$items = range(0, 100);

function do_stuff_with($item) { echo "$item\n"; }

$pids = array();
foreach ($items as $item) {
    $pid = pcntl_fork();
    if ($pid == -1) {
        die("couldn't fork()");
    } elseif ($pid > 0) {
        // parent
        $pids[] = $pid;
    } else {
        // child
        do_stuff_with($item);
        exit(0);
    }   
}

foreach ($pids as $pid) {
    pcntl_waitpid($pid, $status);
}

Jetzt möchte ich dies zu verlängern, so gibt es ein Maximum von etwa 10 Kinder auf einmal aktiv. Was ist der beste Weg, dies zu umgehen? Ich habe ein paar Dinge ausprobiert, aber haben nicht viel Glück gehabt.

War es hilfreich?

Lösung

Es gibt keinen syscall ist eine Liste von Kindern pids zu bekommen, aber ps kann es für Sie tut.

--ppid Schalter werden alle Kinder Liste für Sie verarbeiten, so müssen Sie lediglich die Anzahl der Zeilen von ps ausgegeben zählen.

Alternativ können Sie Ihre eigenen Zähler halten, die Sie auf fork() und Abnahme auf SIGCHLD Signal erhöht werden, unter der Annahme, ppid für fork'ed verarbeitet unverändert bleibt.

Andere Tipps

Das Beste, was ich mit oben kommen kann ist es, alle Aufgaben in eine Warteschlange hinzuzufügen, starten Sie die maximale Anzahl von Threads Sie wollen, und dann haben jeden Thread eine Aufgabe aus der Warteschlange anfordert, führen Sie die Aufgabe und Anforderung der nächste . Vergessen Sie nicht, die Fäden beenden haben, wenn es keine weiteren Aufgaben zu tun.

Parallelruf ist eine teuere Operation. Von den Blicken von ihm, was Sie wirklich wollen, ist Multi Threading , nicht multi Verarbeitung . Der Unterschied besteht darin, dass Gewinde sind viel leichter als Prozesse, da Threads einen virtuellen Adressraum teilen, sondern Prozesse verfügen über separate virtuelle Adressräume.

Ich bin kein PHP-Entwickler, aber eine schnelle Google-Suche zeigt, dass PHP nicht unterstützt nativ Multithreading, aber es gibt Bibliotheken die Arbeit zu tun.

Wie auch immer, wenn Sie herausfinden, wie Threads zu erstellen, sollten Sie herausfinden, wie viele Threads zu erstellen. Um dies zu tun, müssen Sie wissen, was der Engpass Ihrer Anwendung ist. Ist der Engpass CPU, Speicher oder I / O? Sie haben in Ihren Kommentaren angegeben, dass Sie sind netzwerkgebundenen und Netzwerk ist eine Art von I / O.

Wenn Sie die CPU gebunden wurden, wirst du nur so viel Parallelität erhalten, wie Sie CPU-Kerne haben; mehr Threads und Sie nur Zeit verschwenden Kontextwechsel zu tun. Vorausgesetzt, dass Sie herausfinden können, wie viele insgesamt Threads zu erstellen, sollten Sie Ihre Arbeit in so viele Einheiten unterteilen, und haben jeden Thread Prozess eine Einheit unabhängig.

Wenn Sie Speicher gebunden waren, dann würde Multithreading nicht helfen.

Da du bist I / O Bindung heraus herauszufinden, wie viele Threads zu erstellen, ein wenig komplizierter ist. Wenn alle Arbeitselemente in etwa die gleiche Zeit in Anspruch nehmen mit sehr geringer Abweichung zu bearbeiten, können Sie abschätzen, wie viele Threads zu erstellen, durch die Messung, wie lange ein Workitem nimmt. Da jedoch Netzwerk-Pakete sehr variable Latenzen zu haben, neigen dazu, dies ist unwahrscheinlich, dass der Fall sein.

Eine Möglichkeit ist, Thread-Pools zu benutzen - Sie erstellen eine ganze Reihe von Themen, und dann für jedes Element zu verarbeiten, können Sie sehen, ob es ein freier Thread im Pool ist. Wenn ja, haben Sie das Thread die Arbeit durchführen und auf den nächsten Eintrag zu gelangen. Ansonsten warten Sie für einen Thread verfügbar werden. Die Wahl der Größe des Thread-Pool ist wichtig - zu groß, und Sie verschwenden Zeit unnötige Kontextwechsel zu tun. Zu wenig, und du bist für Threads zu oft warten.

Eine weitere Option ist Multithreading / Multiprozessing zu verlassen und tun nur asynchronen I / O statt. Da Sie erwähnt sind Sie auf einem Single-Core-Prozessor arbeiten, wird dies wahrscheinlich die schnellste Option. Sie können Funktionen wie socket_select() zu testen, ob ein Socket Daten verfügbar. Ist dies der Fall, können Sie die Daten lesen, sonst hat man auf eine andere Steckdose zu bewegen. Dies erfordert viel mehr Buchhaltung zu tun, aber Sie vermeiden auf Daten warten auf einen Sockel zu kommen, wenn Daten auf einer anderen Steckdose verfügbar ist.

Wenn Sie Threads zu vermeiden und asynchrones I / O und halten mit Multiprocessing, kann es dennoch sinnvoll sein, wenn die pro-Punkt-Verarbeitung teuer genug ist. Sie könnten dann die Arbeitsteilung tun wie folgt:

$my_process_index = 0;
$pids = array();

// Fork off $max_procs processes
for($i = 0; $i < $max_procs - 1; $i++)
{
  $pid = pcntl_fork();
  if($pid == -1)
  {
    die("couldn't fork()");
  }
  elseif($pid > 0)
  {
    // parent
    $my_process_index++;
    $pids[] = $pid
  }
  else
  {
    // child
    break;
  }
}

// $my_process_index is now an integer in the range [0, $max_procs), unique among all the processes
// Each process will now process 1/$max_procs of the items
for($i = $my_process_index; $i < length($items); $i += $max_procs)
{
  do_stuff_with($items[$i]);
}

if($my_process_index != 0)
{
  exit(0);
}

man 2 setrlimit

Das wird pro Benutzer sein, die können , was Sie wollen auf jeden Fall.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top