jeudi 13 décembre 2012

Utilisation des Runspace (1/2).

Le Runspace est un espace de travail séparé du programme principal qui permet d'exécuter une tâche en parallèle. Prenons les deux exemples suivants. Le premier exemple exécuter deux tâches sans Runspace.

 
#Ouvre une fenêtre.
[Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
$form = New-Object Windows.Forms.Form
$form.Size = New-Object System.Drawing.Size(215,115)
$form.text = "Exemple 1"

#Création label 1 (Label).
$label1 = New-Object Windows.Forms.Label
$label1.Location = New-Object Drawing.Point 20,50
$label1.Size = New-Object Drawing.Point 100,16
$label1.Text = "--------"

#Création bouton 1 (Button).
$bouton1 = New-Object Windows.Forms.Button
$bouton1.Location = New-Object Drawing.Point 20,20
$bouton1.Size = New-Object Drawing.Point 65,21
$bouton1.text = "Tâche 1"
$bouton1.add_click({
                     $label1.Text = "En cours..."
                     $label1.refresh()
                     $i=0;while($i -ne 5000000) {$i++} #Calcule
                     $label1.Text = "Fin."      
                     $label1.refresh()
                  })

#Création label 2 (Label).
$label2 = New-Object Windows.Forms.Label
$label2.Location = New-Object Drawing.Point 120,50
$label2.Size = New-Object Drawing.Point 100,16
$label2.Text = "--------"

#Création bouton 2 (Button).
$bouton2 = New-Object Windows.Forms.Button
$bouton2.Location = New-Object Drawing.Point 120,20
$bouton2.Size = New-Object Drawing.Point 65,21
$bouton2.text = "Tâche 2"
$bouton2.add_click({
                     $label2.Text = "En cours..."
                     $label2.refresh()
                     $i=0;while($i -ne 5000000) {$i++} #Calcule
                     $label2.Text = "Fin."
                     $label2.refresh()
                  })

#Attache le contrôle à la fenêtre.
$form.controls.add($label1)
$form.controls.add($label2)
$form.controls.add($bouton1)
$form.controls.add($bouton2)

#Affiche le tout.
$form.ShowDialog()

#Fin.

Pendant l'exécution de la tâche 1 on remarque qu'il n'est pas possible de lancer la tâche 2. La fenêtre est gelée. Dans le prochain exemple, nous allons exécuter la tâche 1 dans un Runspace (la tâche 2 restera inchangée).

 
#Ouvre une fenêtre.
[Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
$form = New-Object Windows.Forms.Form
$form.Size = New-Object System.Drawing.Size(215,115)
$form.text = "Exemple 2"

#Création du runspace.
$runspace1 = [System.Management.Automation.Runspaces.RunspaceFactory]::CreateRunspace()
$runspace1.Open()

#Création d'un timer pour tester la fin de l'execution du script dans le runspace.
$running = [System.Management.Automation.Runspaces.PipelineState]::Running
$timer1 = new-object System.Windows.forms.timer
$timer1.Interval = (1000) #Milliseconds.
$timer1.Add_Tick({
                   if ($pipeline1.PipelineStateInfo.State -ne $running)
                     {
                       $timer1.Stop()         #Arrêt du timer.
                       $label1.Text = "Fin."  #Signal la fin de l'execution. 
                       $label1.refresh()      #Actualise le contrôle.
                     }
                })

#Création label 1 (Label).
$label1 = New-Object Windows.Forms.Label
$label1.Location = New-Object Drawing.Point 20,50
$label1.Size = New-Object Drawing.Point 100,16
$label1.Text = "--------"

#Création bouton 1 (Button).
$bouton1 = New-Object Windows.Forms.Button
$bouton1.Location = New-Object Drawing.Point 20,20
$bouton1.Size = New-Object Drawing.Point 65,21
$bouton1.text = "Tâche 1"
$bouton1.add_click({
                     $label1.Text = "En cours..."
                     $label1.refresh()
                     #Création du canal de communication avec le runspace.
                      $pipeline1 = $runspace1.CreatePipeline()

                     #Ajout des commande à executer dans le runspace.
                     $pipeline1.Commands.AddScript({
                                                     $i=0
                                                     while($i -ne 5000000) {$i++}
                                                  })

                     #Execution du script dans le runspace.
                     $pipeline1.InvokeAsync()

                     #Lancement du timer pour verifier la fin du traitement.
                     $timer1.Start()            
                  })

#Création label 2 (Label).
$label2 = New-Object Windows.Forms.Label
$label2.Location = New-Object Drawing.Point 120,50
$label2.Size = New-Object Drawing.Point 100,16
$label2.Text = "--------"

#Création bouton 2 (Button).
$bouton2 = New-Object Windows.Forms.Button
$bouton2.Location = New-Object Drawing.Point 120,20
$bouton2.Size = New-Object Drawing.Point 65,21
$bouton2.text = "Tâche 2"
$bouton2.add_click({
                     $label2.Text = "En cours..."
                     $label2.refresh()
                     $i=0;while($i -ne 5000000) {$i++} #Calcule
                     $label2.Text = "Fin."
                     $label2.refresh()          
                  })

#Attache le contrôle à la fenêtre.
$form.controls.add($label1)
$form.controls.add($label2)
$form.controls.add($bouton1)
$form.controls.add($bouton2)

#Affiche le tout.
$form.ShowDialog()

#Libèration
$timer1.Stop()
$runspace1.Close()

#Fin.


Cette fois nous pouvons lancer la première tâche, puis la seconde tâche. Les deux tâches s'exécutent en même temps. Si nous lançons juste la première tâche, nous remarquons que nous pouvons déplacer la fenêtre. Celle-ci n'est pas gelée car la tâche 1 s'exécute dans un espace de travail séparé du programme principal.

Pour aujourd'hui je vais vous épargner l'échange de données entre le programme principal et le Runspace. Mais nous y reviendrons bientôt.