Utilisation de proc_open et pcntl : conflit ?
Bonjour,
Je suis actuellement en train de paralléliser des calculs écris en PHP.
Il y a 12 familles de calcul à paralléliser, puis, dans chaque famille, on veut lancer 1 à n calculs en //.
La première étape a consisté à tester les 2 parallélisation séparément:
Le script "Père" lance 12 scripts "fils" (les 12 familles de calcul) en // avec proc_open. Celà fonctionne correctement.
Un script fils lance des calculs en parallèle avec la fonction pcntl_fork. Celà fonctionne correctement.
Cependant, si l'on fait tout fonctionner en même temps, il y a trop de calculs lancés. Chaque famille de calcul est lancée plusieurs fois. Je n'arrive pas à comprendre ce qui se passe.
Voici un extrait du script "Père" qui va lancer les 12 familles de calcul:
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
|
// Boucle sur les id_group_table des familles à traiter
foreach ( $listGroupTable as $id_group_table => $tableau_info_famille )
{
$descriptorspec = array();
$pipes = array();
$env = array( "env_id_group_table" => $id_group_table );
displayInDemon( "Launch compute raw process for group table $id_group_table" );
$procFile = dirname( $PHP_SELF )."/le_fils.php";
$h = proc_open("php $procFile", $descriptorspec, $pipes, NULL, $env );
// Test si le process s'est bien lancé
if( $h !== false )
{
$listHandle[]= $h;
}
else
{
displayInDemon( 'Error lors du lancement du group table '.$id_group_table, 'alert' );
}
}
displayInDemon( 'All processes started, now check end execution every milliseconds...' );
$listPidExecuted = array();
$nbProcesses = count( $listHandle );
while( count( $listPidExecuted ) !== $nbProcesses )
{
foreach( $listHandle as $oneHandle )
{
$a = proc_get_status( $oneHandle ); // Lecture de l'état du process
//
// Si le process vient de se terminer
if( $a['running'] == false && !in_array( $a['pid'], $listPidExecuted ) )
{
$listPidExecuted[] = intval( $a['pid'] );
displayInDemon( "{$a['pid']} est terminee" );
}
}
usleep( 1000 ); // On attend 1ms avant le prochain test
}
displayInDemon( 'Process execution ended' ); |
Et voici un extrait de la classe appelée dans "le_fils.php" pour la parallélisation des calculs
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
// Dans la boucle des calculs:
if( !$pcntl_started )
{
declare(ticks=1);
$pcntl_started = true;
$this->parentPID = getmypid();
$this->currentJobs = $this->signalQueue = array();
pcntl_signal(SIGCHLD, array($this,"childSignalHandler") );
}
// On attend qu'un slot se libère pour lancer un processus
while( count($this->currentJobs) >= $maxProcesses )
usleep(100);
// Lancement d'un calcul
$jobID = current($this->freeJobs);
displayInDemon("Lancement d'un calcul dans le slot $jobID");
$this->launchProcess($currentInstructions['queries'], $jobID, $index);
// [...]
// Après la boucle des calculs:
// On attend que les requêtes en cours soient terminées
while(count($this->currentJobs) > 0) usleep(100); |
Méthode launchProcess:
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
|
public function launchProcess(array $queries, $jobID, $index)
{
// Création d'un processus fils
$pid = pcntl_fork();
if($pid == -1)
{
// Impossible de créer le processus
displayInDemon("Unable to fork compute calculation. Calculation failed.",'alert');
return false;
}
else if ( $pid )
{
// Parent process
// Sometimes you can receive a signal to the childSignalHandler function before this code executes if
// the child script executes quickly enough!
$this->currentJobs[$pid] = $jobID;
$this->freeJobs = array_diff($this->freeJobs, $this->currentJobs);
// In the event that a signal for this pid was caught before we get here, it will be in our signalQueue array
// So let's go ahead and process it now as if we'd just received the signal
if(isset($this->signalQueue[$pid]))
{
$this->childSignalHandler(SIGCHLD, $pid, $this->signalQueue[$pid]);
unset($this->signalQueue[$pid]);
}
}
else
{
// Lacement des calculs
$db = new DataBaseConnection();
$queryResults = $this->executeComputeQuery($queries, $db);
$this->setQueryResults($index, $queryResults);
$db->close();
exit(0);
}
} |
La méthode utilisée avec pcntl est tirée d'un exemple dans la page de doc:
http://www.php.net/manual/fr/functio...fork.php#98711
Mer de votre aide.
PHP 5.2.13
RedHat Linux EL 5.5 64bits