herbstengel
Goto Top

Powershell: Unterstützung bei Start-Job benötigt im Hinblick auf Ein- und Ausgabeparameter

Hallo Community,

ich bräuchte bitte mal wieder etwas "Nachhilfe" zum Thema Start-Job bei Powershell.

Ich habe dazu folgende Aufgabe "konstruiert": Es handelt sich um einen Prozess (Division mit Restwertvorgabe) der vier Eingabe- und zwei Rückgabewerte verwertet.

Eingabewerte: Nummernbereich 0...100, Divisor, Divisionsrest, Quotient; Ausgabe: Ergebnis und Merker für Schleifenabbruch, d.h. erstem Treffer

verbale Formulierung:
Aus dem vorgegebenen Nummernbereich soll diejenige Zahl gefunden werden, bei welcher der vorgegebene Divisionsrest erreicht wird, sobald der vorgegebene Quotient den
angegebenen ganzzahligen (Mindest)wert erreicht hat. Als Ergebnis soll die gefundene Zahl und ein Merker für den Treffer ausgegeben werden:

zunächst die Variante ohne Start-Job:

[bool]$FinishLoop = $false
[int] $divisor = 42
[int] $divisionsrest = 7
[int] $quotient = 1
[int] $result = 0
$numbers = 0..100
Clear-Host
$numbers | ForEach-Object `
          {
              start-sleep -m 50; `
              write-host $_
              if(  $_ % $divisor -eq $divisionsrest -and $_ / $divisor -ge $quotient -and !$FinishLoop)
              {
                   #Write-Host "Treffer mit Wert $_" 
                   $result = $_
                   $FinishLoop = $true
                   return
              }
          }

Write-Host ""  
Write-Host "Fertig mit ForEach-Object über den Bereich $numbers zum Bestimmen der Zahl aus diesem Bereich mit einem Divisionsrest von $divisionsrest, wenn die Division mit $divisor mindestens groesser/gleich $quotient ist"  
Write-Host ""  

Write-Host "Ergebnis: $result"  
Write-Host "FinishLoop hat den Wert $FinishLoop"   

Funktioniert soweit einwandfrei:
97
98
99
100

Fertig mit ForEach-Object über den Bereich 0 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 42 43 44 45
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 zum
Bestimmen der Zahl aus diesem Bereich mit einem Divisionsrest von 7, wenn die Division mit 42 mindestens groesser/gleich 1 ist

Ergebnis: 49
FinishLoop hat den Wert True


Nun habe ich den Prozessablauf auf Start-Job umgebaut. Um die Suche im Hintergrund ablaufen zu lassen und ggf. einen Warteablauf ablaufen zu lassen.
Leider ist da mindestens ein entscheidender Fehler drin, denn die while-Schleife wird nicht verlassen: Endlosschleife.
Ich habe natürlich so gut es ging recherchiert, komme aber leider nicht weiter und benötige die Unterstützung von euch, vielen Dank schon mal.

Grüsse, Roger


bool]$FinishLoop = $false
[int] $divisor = 42
[int] $divisionsrest = 7
[int] $quotient = 1
[int] $result = 0
$numbers = 0..100  #PSObject
Clear-Host
start-job -argumentlist $numbers, $divisor, $divisionsrest, $quotient, [ref]$FinishLoop, [ref]$result  `
          -Name "MyJob" `  
          -scriptblock {
          
          param ($p_numbers, $p_divisor,$p_divisionsrest,$p_quotient,[ref]$p_FinishLoop, [ref]$p_result)
          $p_numbers | ForEach-Object `
          {
              start-sleep -m 50; `
              write-host $_
              if(  $_ % $p_divisor -eq $p_divisionsrest -and $_ / $p_divisor -ge $p_quotient -and !$p_FinishLoop)
              {
                   #Write-Host "Treffer mit Wert $_" 
                   $p_result = $_
                   $p_FinishLoop = $true
                   return
              }
          }
          }
while ((Get-Job -Name "MyJob").State -ne "Completed")  
{
    Write-Host "Berechnung laeuft, mache dann was anderes"  
    #hier weitere Aktion starten
}
Write-Host ""  
Write-Host "fertig"  

(Get-Job -Name "MyJob") | receive-job  


Write-Host ""  
Write-Host "Fertig mit ForEach-Object über den Bereich $numbers zum Bestimmen der Zahl aus diesem Bereich mit einem Divisionsreste von $divisionsrest, wenn die Division mit $divisor mindestens groesser/gleich $quotient ist"  
Write-Host ""  

Write-Host "Ergebnis: $result"  
Write-Host "FinishLoop hat den Wert $FinishLoop"   

Content-Key: 563124

Url: https://administrator.de/contentid/563124

Printed on: April 20, 2024 at 09:04 o'clock

Mitglied: 143728
Solution 143728 Apr 05, 2020 updated at 07:17:57 (UTC)
Goto Top
[int] $divisor = 42
[int] $divisionsrest = 7
[int] $quotient = 1
$numbers = 0..100
Clear-Host
$job = start-job -argumentlist $numbers, $divisor, $divisionsrest, $quotient -Name "MyJob" -scriptblock {  
          param ($p_numbers, $p_divisor,$p_divisionsrest,$p_quotient)
          return ($p_numbers | ?{$_ % $p_divisor -eq $p_divisionsrest -and $_ / $p_divisor -ge $p_quotient} | select -F 1)
}

$result = $job | receive-job -wait

Write-Host ""  
Write-Host "Fertig über den Bereich $numbers zum Bestimmen der Zahl aus diesem Bereich mit einem Divisionsreste von $divisionsrest, wenn die Division mit $divisor mindestens groesser/gleich $quotient ist"  

Write-Host "Ergebnis: $result"  
Member: Herbstengel
Herbstengel Apr 05, 2020 at 12:41:03 (UTC)
Goto Top
Hallo caprinha,

danke für Deine Antwort. Hat mir gezeigt dass ich nicht ganz falsch lag. Du hast mir aber die while-Schleife und das Foreach-Object herausgestrichen. Das sollte schon drin bleiben. Ich habe nun eine Lösung gefunden, die nach meinen Vorstellungen funktioniert, s.u.

Eine Spezialfrage noch: kann man in der Argumenten- und Parameterliste von Start-Job auch Referenztypen übergeben? z.B.
[ref]$result (argumentlist) bzw. [ref]$p_result (param_liste). Im Scriptblock könnten man dann mit $p_result.value eine Wertzuweisung
machen und diesen Wert dann im Hauptlauf mit $result weiterverarbeiten...

Bisher meckert mir das powershell aber an

[int] $divisor = 42
[int] $divisionsrest = 7
[int] $quotient = 1
[int] $result = 0
[bool]$finishLoop = $false
[string] $backgroundJobName = "MyJob"  
[PSObject] $numbers = 0..100
Clear-Host

start-job `
   -argumentlist $numbers, $divisor, $divisionsrest, $quotient, $finishLoop `
   -Name $backgroundJobName `
   -scriptblock `
   {
       param ($p_numbers, $p_divisor,$p_divisionsrest,$p_quotient,$p_finishLoop) #p_ steht fuer Parameter
       $p_numbers | ForEach-Object `
       {
           start-sleep -m 25; `
           write-host $_
           if(  $_ % $p_divisor -eq $p_divisionsrest -and $_ / $p_divisor -ge $p_quotient -and !$p_finishLoop)
           {
               Write-Host "Treffer mit Wert $_"  
               $p_FinishLoop = $true
               return ($_)
           }
       }
   }
Write-Host ""  
Write-Host "Die Verarbeitung von $backgroundJobName wurde im Hintergrund angestartet"  
Write-Host ""  

while ((Get-Job -Name "MyJob").State -ne "Completed")  
{
    Write-Host "Verarbeitung von $backgroundJobName laeuft im Hintergrund, mache dann ggf. parallel zur diesem Hinweis was anderes"  
    #hier weitere Aktion starten
}
Write-Host ""  
Write-Host "Verarbeitung von $backgroundJobName im Hintergrund wurde beendet"  

$result = (Get-Job -Name $backgroundJobName) | receive-job #return-Wert return ($_) d.h. gesuchter Treffer wird abgeholt
(Get-Job -Name $backgroundJobName) | remove-job #Job wird dann gleich geloescht

Write-Host ""  
Write-Host "-----------------------"  

Write-Host "Fertig!"  
Write-Host "über den Bereich $numbers zum Bestimmen der Zahl aus diesem Bereich mit einem Divisionsrest von $divisionsrest, wenn die Division mit $divisor mindestens groesser/gleich $quotient ist"  

Write-Host ""  
Write-Host "Ergebnis: $result"   
Write-Host ""  
Write-Host "-----------------------"  
Write-Host "-----------------------"  
Mitglied: 143728
Solution 143728 Apr 05, 2020 updated at 13:21:59 (UTC)
Goto Top
Zitat von @Herbstengel:

Hallo caprinha,
Also für eine Caprisonne bin ich dann doch schon zu alt face-big-smile.
Du hast mir aber die while-Schleife und das Foreach-Object herausgestrichen.
Macht aber genau das selbe ohne das überflüssige Gedöhns face-wink

Eine Spezialfrage noch: kann man in der Argumenten- und Parameterliste von Start-Job auch Referenztypen übergeben? z.B.
Nein, ein Job wird in einem anderen Thread ausgeführt.
Für separate Threads nutzt man heutzutage aber eher Runspaces anstatt Jobs (Jobs sind ja ehrlich gesagt ziemlich lahm ...) und nutzt dann eine synced Hashtable die zwischen den Threads synchronisiert wird.
Alternativ wenn Parallelisierung gewünscht ist kann man auch mit Powershell Workflows arbeiten.
Du kannst auch in dem Job ein PSObject mit allen deinen Werten als Eigenschaften zurückgeben und dann im Hauptthread aus dem Object abfragen.
Member: Herbstengel
Herbstengel Apr 05, 2020 updated at 19:12:58 (UTC)
Goto Top
Hallo cabrinha,

erneut danke für Deine Antwort. Da ich noch ein ziemlich blutiger Powershell-Anfänger bin, habe ich mich für den Weg mit einem PSObject , worin meinen beiden "Return-Werte" als Eigenschaften enthalten sind, die beide dann im Hauptthread aus dem Object abgefragt werden. Code: s.u.

In der while-Schleife läuft im eigentlichen Projekt dynamisch eine Progressbar in einer GUI. Die brauche ich dann schon.

Ich musste mir ein diesem konstruiertem Beispiel erstmal mein Verständnis für die Anwendung von Start-Job schärfen.

Ich denke das ist mir nun soweit klar. Vielleicht kann jemand anderes auch noch was damit anfangen...

Anfrage hiermit aus meiner Sicht gelöst face-smile

viele Grüsse, Roger

#initialisierung Eingabevariable/Objekt
[PSObject] $numbers = 0..100
[int] $divisor = 42
[int] $divisionsrest = 7
[int] $quotient = 1
[bool]$finishLoop = $false

#initialisierung Ausgabevariable/Objekt
[PSCustomObject]$returnObj=  @()
[int]$resultSolutionValue = -1
[bool]$resultFirstHitInLoop = $false

#Name Hintergrundjob
[string] $backgroundJobName = "MySpecialBackgroungJob"  


Clear-Host

start-job `
   -argumentlist $numbers, $divisor, $divisionsrest, $quotient, $finishLoop `
   -Name $backgroundJobName `
   -scriptblock `
   {
       param ($p_numbers, $p_divisor,$p_divisionsrest,$p_quotient,$p_finishLoop) #p_ steht fuer Parameter

       #Rueckgabewerte der Routine
       $retObj = [PSCustomObject] `
       @{
            solutionValue = -1
            finishLoop    = $false
       }

       #Routine: verarbeitet Eingaben, liefert Ausgaben
       $p_numbers | ForEach-Object `
       {
           start-sleep -m 25; `
           write-host $_
           if(  $_ % $p_divisor -eq $p_divisionsrest -and $_ / $p_divisor -ge $p_quotient -and !$p_finishLoop)
           {
               Write-Host "Treffer mit Wert $_"  
               $p_FinishLoop = $true

               $retObj.solutionValue = $_
               $retObj.finishLoop = $p_FinishLoop

               return ($retObj)
           }
       }
   }
Write-Host ""  
Write-Host "Die Verarbeitung von $backgroundJobName wurde im Hintergrund angestartet"  
Write-Host ""  

while ((Get-Job -Name $backgroundJobName).State -ne "Completed")  
{
    Write-Host "Verarbeitung von $backgroundJobName laeuft im Hintergrund, mache dann ggf. parallel zur diesem Hinweis was anderes"  
    #hier weitere Aktion starten
}
Write-Host ""  
Write-Host "Verarbeitung von $backgroundJobName im Hintergrund wurde beendet"  
Write-Host ""  
Write-Host "Darstellung der Verarbeitung:"  

#Verarbeitungsergebnis wird abgeholt
$returnObj = (Get-Job -Name $backgroundJobName) | receive-job
#Job wird dann gleich geloescht
(Get-Job -Name $backgroundJobName) | remove-job

#Ausgabeteil: in Variblen und aus Konsole
Write-Host ""  
Write-Host "----E R G E B N I S---"  

Write-Host "Fertig!"  
Write-Host "über den Bereich $numbers zum Bestimmen der Zahl aus diesem Bereich mit einem Divisionsrest von $divisionsrest, wenn die Division mit $divisor mindestens groesser/gleich $quotient ist"  

Write-Host ""  
$resultSolutionValue  = $returnObj | Select-Object -ExpandProperty solutionValue
$resultFirstHitInLoop = $returnObj | Select-Object -ExpandProperty finishLoop

Write-Host "Ergebniswert: $resultSolutionValue"  
Write-Host "erster Treffer in Suchschleife liegt vor: $resultFirstHitInLoop"  

Write-Host "----------------------"  
Write-Host "-------E N D E--------"