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 : Sélectionner tout - Visualiser dans une fenêtre à part
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 : Sélectionner tout - Visualiser dans une fenêtre à part
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 : Sélectionner tout - Visualiser dans une fenêtre à part
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