PowerShell Umsetzungfrage Array vs Arraylist ForEach - parallel

pizza4ever

Lt. Commander
Registriert
Apr. 2009
Beiträge
1.665
Hallo zusammen,

ich schreibe gerade meinen Code für das Powershell V7 -parallel um und habe dazu eine Umsetzungsfrage:

Ich möchte einen größeren Block per Foreach Parallelisieren, der theoretisch gut parallelisierbar ist und am Ende einen Webservice aufruft.

Im Endeffekt bekomme ich es nicht hin, obwohl ich brav die Regeln die MS gepostet hat versucht habe einzuhalten und Teile / Unit Tests auch zu funktionieren, das Zusammengebaute aber nicht.

Nun ist meine Idee folgende:

Ich zerlege das Foreach in zwei Teile:
1.) Sequentiellen Teil, der mir die Aufrufe aufbaut (der ist eh schnell)
2.) Parallelisierten Teil, der die in 1.) zusammengestellte Aufrufe nur noch per Invoke-RestMethod ausführt.

Hierfür ist meine Idee:

in 1.) Baue ich ein - und das ist meine Frage - Powershell Object? auf, welches ein Array (Arraylist?) sein muss welches ich dann an Invoke Restmethod schicke?

Das Objekt - oder wie auch immer es umgesetzt werden soll - sollte in in Etwa wie folgt aussehen:

Bezeichnung | HDD-Pfad | JSON Request | JSON Response (muss von 2.) befüllt werden) | noch ein paar sonstige Integers

Dieses Objekt würde ich dann per Foreach in 2.) an Invoke Restmethod übergeben.

Fragen:

  • ist mein Ansatz richtig, das Foreach zu zerlegen und nur den zeitkritischen Pfad zu parallelisieren? Mir scheint es so, dass man bei Foreach - Parallel kaum noch vernünftig debuggen kann und daher kam ich auf die Idee.
  • Welches Objekt sollte ich wählen und wie muss das aufgebaut sein? Ein Globales Arraylist aus Powershell-Objekten? (Ja, ich vermeide globale Variablen auch wo es geht)

Danke für eure Einschätzung.
 
Mit dem neuen Parameter für parallelisierter Verarbeitung kann man sehr viel Zeit sparen, wenn intelligent eingesetzt.
Allerdings nur, wenn man auf keine explizite Antwort wartet.
Zumindest hab ich nichts anderweitig gelesen, was den neuen Parameter angeht.

Zur Info:
Das Ganze konnte man schon länger ... mit diversen Ansätzen.
Einen davon hab ich bereits vor einiger Zeit vorgestellt (2017; RunspaceFactory via PowerShell),
https://www.computerbase.de/forum/t...ded-von-einer-webseite-herunterladen.1719517/
der aber sehr speziell ist und auf jeden Fall noch performanter gestaltet und besser "Generic" angepasst werden kann.


Wobei scheiterts denn aktuell?
 
Zuletzt bearbeitet:
So richtig seh ich da grad bei der Frage nicht durch. 😕

Arraylists und Invoke-* haben mit Foreach-Object überhaupt nichts zu tun, das ist ein stinknormales Foreach, nur halt parallel abgearbeitet.
Man geht da also genauso ran wie "normales" Foreach:

PowerShell:
$a, $b, $c | 
foreach-object -parallel { $_ }

Gemäß OP würde ich vorschlagen, zunächst erstmal eine Iteration anzulegen und zu testen. Wenn das funktioniert, foreach-object non-parallel. Das sollte dann prinzipiell gleich funktionieren... aber lieber wissen und nicht glauben.
Dann -parallel und gucken.

Und bei -parallel darauf achten, daß Schreibaufträge wahnsinnig interessant werden können. Threadlokale Variablen (alles was es nur im Scriptblock von Foreach gibt) sind egal, aber wenn reingefütterte Variablen verändert werden... wird das vermutlich schiefgehen.

Dasselbe gilt auch für den externen Aufruf. Kommt der Webservice mit den parallelen Anfragen klar? Wenn ja, prima. Wenn nicht, was einfallen lassen.

Was die Aufteilung angeht.. alles was dauert und was aber auch keine besonderen Abhängigkeiten hat, kann parallelisiert werden. Besonders, wenn es mehrere Dinge gibt, die länger dauern. Wenn man parallel rangeht, dann kann man eine Aufgabe anschieben, sobald ihre Vorbedingungen alle erfüllt sind -- NICHT wie traditionell dann, wenn man das Ergebnis dafür benötigt, sondern ggfs lange vorher.

Ich hab zB in meiner Bibliothek eine Referenzimplementierung für paralleles Extrahieren von CAB-Dateien in PS. Da werden #Cores CABs gleichzeitig ausgepackt. Funktioniert natürlich nur sinnvoll schnell, wenn man nicht auf HDDs schreibt - aber unter der Annahme daß die Dateien alle größer sind, geht das so signifikant schneller als nacheinander.

Eine anderer Anwendungszweck sind komplette Prozesse. VM hochfahren, Zeug installieren, was prüfen, runterfahren => ein Prozeß. Viele VMs => derselbe Prozeß wird 1x bis maximal #VMs gleichzeitig gestartet. Somit dauert im Idealfall der Gesamtverlauf 1x Prozeßlaufzeit statt Anzahl VMs x Prozeßlaufzeit.

Je weniger zu tun ist, desto weniger lohnt sich das, und wenn es Abhängigkeiten gibt, wird's noch richtig interessant. In solchen Fällen kann man sich, wenn man das will, einen Abhängigkeitsbaum basteln und dann multithreaded abarbeiten... aber das ist aufwendig und man muß das Ursprungsproblem ausreichend gut segmentieren können.

Irgendwann ist dann auch der Punkt da, wo der Gesamtaufwand größer ist als der Nutzen. Muß man also abwägen.
 
RalphS schrieb:
So richtig seh ich da grad bei der Frage nicht durch. 😕

Arraylists und Invoke-* haben mit Foreach-Object überhaupt nichts zu tun, das ist ein stinknormales Foreach, nur halt parallel abgearbeitet.
Man geht da also genauso ran wie "normales" Foreach:

PowerShell:
$a, $b, $c |
foreach-object -parallel { $_ }

Ganz so einfach ist es leider nicht, man muss ja (externe) Variablen mit using: deklarieren.

Ich habs nun mit viel Schweiss und perlen umgebaut, dass es klappt (und zum laufen bekommen)...

Ergebnisse sind bei 220 Webservice Aufrufen:

j=1, nonparallel, kompletter Durchlauf:
00:01:22.0132006
j=1, parallel, kompletter Durchlauf:
00:00:40.5481331



j=6, nonparallel, kompletter Durchlauf:
00:06:23.7665053
j=6, parallel, kompletter Durchlauf:
00:00:45.1544826

j ist einfach nur ein Faktor der das ganze in einer Dimension erweitert (ob die For Schleife nur ein Feld prüft oder 6 Felder)

Anmerkung: es gibt einen Offeset durch Downloaden aus Daten vom SQL Server vorher, aber die Parallelisierung hat schon das ganze erheblich beschleunigt.
 
Zurück
Oben