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:
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
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' );
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 // 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);
La méthode utilisée avec pcntl est tirée d'un exemple dans la page de doc:
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); } }
http://www.php.net/manual/fr/functio...fork.php#98711
Mer de votre aide.
PHP 5.2.13
RedHat Linux EL 5.5 64bits
Partager