- PowerShell Ponúka viacero spôsobov iterácie (foreach, ForEach-Object, metóda ForEach, for, while, do-while, do-until) s rôznymi dôsledkami pre výkon a pamäť.
- ForEach-Object -Parallel v PowerShell 7 umožňuje paralelné spracovanie prvkov kanála, riadenie súbežnosti prostredníctvom ThrottleLimit a obetovanie poradia výstupu.
- Start-Job, Start-ThreadJob, behové priestory a staršie pracovné postupy s foreach -Parallel poskytujú ďalšie modely paralelizmu s rôznymi preťaženiami a úrovňami izolácie.
- Meranie výkonu, vyhýbanie sa typickým chybám foreach a uplatňovanie dobrých postupov riadenia toku a spracovania chýb sú kľúčom k budovaniu výkonných a stabilných kanálov.

Keď začnete pracovať s PowerShellom, skôr či neskôr narazíte na rovnaký problém: máte veľa objektov na spracovanie v slučke a výkon prudko klesá. Vymieňajte si poštové schránky, súbory na serveri, procesy na viacerých počítačoch, napríklad pre spravovať viacero počítačov a serverov...všetko ide cez kanál a klasika ForEach-ObjectAle samozrejme, táto slučka ide prvok po prvku, postupne, a príde bod, kedy zlyhá.
S príchodom PowerShellu 7 sa situácia značne zmenila. Teraz máme k dispozícii paralelné zreťazenie s ForEach-Object -Parallel a ďalšie prístupy k súbežnosti, ktoré umožňujú lepšie využitie jadier CPU a čas čakanie na sieťové alebo diskové operácie. Trik spočíva v pochopení toho, čo každá možnosť robí, kedy ju použiť a ako obmedziť súbežné operácie, aby sa výkon neznižoval namiesto jeho zlepšovania.
Slučky v PowerShelle: východiskový bod
Predtým, ako sa ponoríme do paralelných pipeline, je užitočné pochopiť, čo sú slučky a ako sa správajú rôzne konštrukty PowerShellu. Slučka je v podstate spôsob, akým zopakujte jeden alebo viacero pokynov viackrátMôže to byť pre známy počet iterácií alebo kým je splnená podmienka. V systémovej administrácii je to bežné: od prideľovania oprávnení všetkým používateľom v skupine až po prechádzanie tisíckami súborov v adresári alebo spracovanie udalostí s Get-WinEvent.
PowerShell ponúka niekoľko klasických riadiacich štruktúr, ako napríklad for, foreach, while, do-while y do-until, okrem cmdletov a metód, ktoré tiež umožňujú iteráciu, ako napríklad ForEach-Object alebo metóda .ForEach() v kolekciách. Všetky tvoria základ, na ktorom potom môžeme budovať pokročilejšiu logiku vrátane paralelného vykonávania.
foreach vs ForEach-Object vs metóda ForEach
V PowerShelle je určitý zmätok, pretože máme tri rôzne spôsoby vykonania príkazu „foreach“ A nesprávajú sa rovnako. Syntakticky sú si podobné, ale vnútorne sa veci dosť menia, najmä čo sa týka využitia pamäte a kanálov.
kľúčové slovo foreach (príkaz foreach)
Kľúčové slovo foreach Je to „klasická“ konštrukcia cyklu v jazyku. Načítajte Celá kolekcia je uložená v pamäti a každý prvok sa prechádza postupne.Je to pohodlné a veľmi rýchle, keď už máte v pamäti pole alebo inú kolekciu a jej veľkosť je primeraná. Spracovanie prebieha podľa týchto krokov: najprv PowerShell určí, koľko prvkov existuje, potom každý prvok jeden po druhom priradí premennej (napríklad $item) a vykoná blok kódu pre každú iteráciu.
Tento prístup je ideálny, keď Pracujete s dobre definovanými pamäťovými kolekciamiako napríklad zoznam procesov, sada trás alebo rozsah čísel. Nie je však určený na priame čítanie z kanála a ak je kolekcia veľmi veľká, môže spotrebovať značné množstvo pamäte.
cmdlet ForEach-Object v kanáli
Rutina cmdlet ForEach-Object Funguje to inak: je to navrhnuté tak, aby spracovávať jeden objekt naraz, hneď ako prichádza cez kanálInými slovami, nemusí mať celú kolekciu načítanú od začiatku. Vďaka tomu je veľmi efektívny v scenároch, kde zdroj údajov môže generovať veľa položiek (napríklad Get-ChildItem (v obrovskom stromovom priečinku) alebo keď nechcete alebo nemôžete uložiť celú kolekciu do pamäte, alebo pri použití externých nástrojov, ako napríklad Git z PowerShellu.
Na oplátku, Má mierne preťaženie kvôli samotnému mechanizmu pipeline a je zvyčajne o niečo pomalší ako kľúčové slovo foreach keď oba pracujú na tej istej kolekcii v pamäti. Získava to však body v škálovateľnosti a efektívnosti pamäte, čo je v produkčných prostrediach zvyčajne dôležitejšie ako skrátenie rýchlosti o niekoľko milisekúnd na objekt.
Metóda ForEach() v kolekciách
Od verzie PowerShell 5 túto metódu sprístupňuje mnoho kolekcií, ako sú polia a zoznamy. .ForEach(), čo umožňuje Veľmi stručným spôsobom aplikujte skriptový blok na každý prvok, Napríklad, $array.ForEach({ ... })Táto metóda je objektovo orientovaná a je veľmi užitočná, keď chcete reťaziť operácie a hladko pracovať s už existujúcimi kolekciami.
Z hľadiska výkonu, metóda .ForEach() zvyčajne efektívnejšie ako cmdlet ForEach-Object Keď je už všetko v pamäti, pretože sa vyhnete časti mechaniky spracovania dát. Napriek tomu má rovnaké základné obmedzenie: funguje na kolekciách, ktoré už boli materializované, takže nie je vhodným nástrojom na streamovanie veľkých objemov údajov.
Praktické rozdiely medzi foreach a ForEach-Object
V každodennej praxi sa vynárajú otázky typu: „Prečo je to tak?“ scenár Spojené štáty americké Get-Mailbox ... | ForEach-Object { ... } a ďalší to urobí prvý $Mailboxes = Get-Mailbox ... a potom a foreach ($Mailbox in $Mailboxes)Hlavný rozdiel je v tom, že v prvom prípade Všetko prechádza cez kanál, ktorý spracováva každú poštovú schránku hneď po jej príchode., zatiaľ čo v druhom prípade je celá kolekcia uložená v premennej $Mailboxes a potom cestujete po okolí.
Voľba nie je len otázkou štýlu: ak šoférujete tisíce prvkov, využitie pamäte a spracovanie chýb Môžu sa dosť líšiť a práve v tomto prípade je kanál zvyčajne úspornejší z hľadiska spotreby, za cenu miernych nákladov na výkon na objekt.
Iné typy slučiek: for, while, do-while, do-until
Okrem ekosystému foreach obsahuje PowerShell aj ďalšie tradičné cykly, ktoré sú stále veľmi užitočné. Cyklus foreach for umožňuje iteráciu v rozsahu číselDobrým nápadom je zvyšovať alebo znižovať index, kým nie je splnená podmienka. Je to perfektné na prechádzanie poliami podľa pozície, preskakovanie prvkov alebo ich spätný prístup.
slučky do-while y do-until Popravia telo aspoň raz a potom skontrolujú podmienku: v do-while opakuje sa tak dlho, ako je naplnené, a v do-until Opakuje sa, kým nie je splnená podmienka. Tieto funkcie sú veľmi užitočné, keď potrebujete, aby sa blok vykonal aspoň raz, napríklad pri vyžiadaní údajov od používateľa alebo pri testovaní zdroja, kým neodpovie správne.
Slučka while zhodnoťte situáciu hneď na začiatkuAk podmienka nie je splnená, nedostane sa do systému. Je to klasické „pokiaľ toto zostáva pravdivé“, ktoré všetci poznáme z iných jazykov. V automatizačných úlohách sa dá použiť na monitorovanie služby, číselnej hodnoty alebo stavu zdroja, kým sa nedosiahne cieľ.
Jemné riadenie toku: prerušenie, pokračovanie a návrat
Pre lepšiu kontrolu nad tým, čo sa deje vo vnútri slučiek, máme tri kľúčové kľúčové slová: break, continue y returnHoci sa niekedy prehliadajú, v zložitých skriptoch majú veľký význam.
Pokyn break Umožňuje vám okamžite ukončiť slučku. aktuálne. Je to veľmi užitočné, keď prechádzate poľom alebo zoznamom a hľadáte niečo konkrétne: hneď ako to nájdete, break a ušetríte si zbytočné opakovanie.
Slovo continue skok na ďalšiu iteráciu slučkyignorovanie zvyšku inštrukcií v aktuálnej iterácii. Často sa používa na „filtrovanie“ prvkov: ak niečo nespĺňa podmienku, spĺňate ju continue a skutočne spracovávaš len to, čo ťa zaujíma.
konečne, return nielenže preruší slučkuNielenže vracia hodnotu z funkcie alebo skriptu, ale vracia aj hodnotu zo samotného skriptu. Je to ako povedať: „Mám, čo som hľadal, tu to je a odchádzam.“ Pri rozumnom použití výrazne zjednodušuje logiku skriptu.
ForEach-Object -Parallel v PowerShell 7
PowerShell 7 predstavil veľmi výkonnú novú funkciu: parameter -Parallel cmdletu ForEach-ObjectTáto funkcia, pôvodne pridaná v beta verzii 7.0, umožňuje spracovanie viacerých prvkov kanála naraz bez nutnosti použitia externých modulov alebo zložitého kódu s runspace.
Myšlienka je jednoduchá: namiesto postupného spracovania jedného objektu za druhýmRutina cmdlet môže spustiť viacero iterácií paralelne, pričom každá z nich vykoná blok skriptu na inom prvku kolekcie. Týmto spôsobom, ak máte nezávislé úlohy (ako napríklad viacero požiadaviek HTTP, viacero kópií súborov do rôznych cieľov alebo dotazy voči mnohým poštovým schránkam), môžete výrazne skrátiť celkový čas vykonávania.
Správanie ForEach-Object pred a po -Parallel
Bez parametra -Parallel, Funkcia ForEach-Object spracováva prvky v poradíJeden po druhom, čakajúc na dokončenie každého bloku predtým, ako prejdete na ďalší. Ak urobíte jednoduchý test s 10 objektmi a krátkou umelou pauzou, uvidíte, že celkový čas je prakticky súčtom 10 jednotlivých časov.
Aktivuje sa -Parallel Ten istý kód sa dá vykonať niekoľkokrát rýchlejšie.Je to preto, že iterácie sú rozdelené medzi niekoľko podprocesov. Typický príklad: to, čo v sekvenčnom režime trvá približne 10 sekúnd, sa môže v paralelnom režime skrátiť na menej ako 3 sekundy v závislosti od počtu simultánnych úloh a typu práce, ktorú v rámci bloku vykonávate.
Poradie ukončenia a počet simultánnych operácií
Je tu jeden dôležitý detail: keď používate ForEach-Object -Parallel, Poradie výsledkov už nie je zaručené.Položky sa vracajú po dokončení úloh, nie v pôvodnom poradí. Ak vaša logika závisí od poradia, budete ich musieť následne znova zoradiť alebo zahrnúť indexové informácie na jeho rekonštrukciu.
Predvolene sa spúšťa PowerShell 7 päť simultánnych operáciíAk to potrebujete upraviť, použite parameter ThrottleLimitToto definuje maximálny počet prvkov, ktoré je možné spracovať súčasne. Správna konfigurácia je kľúčom k nájdeniu správnej rovnováhy medzi rýchlosťou a spotrebou zdrojov.
Kedy nie je vhodné paralelizovať?
Nie všetky problémy sa dajú vyriešiť bez rozdielu porovnávaním. V niektorých scenároch, ako napríklad prenos veľkých súborov cez obmedzenú sieťSpúšťanie príliš veľkého množstva operácií paralelne môže preťažiť šírku pásma a paradoxne všetko spomaliť. To isté platí pre API alebo vzdialené služby, ktoré majú limity požiadaviek.
V iných prípadoch, ako napríklad pri operáciách, ktoré závisia výlučne od príkaz na vykonanie alebo ktoré upravujú ten istý zdieľaný zdrojParalelizmus môže viesť k súbehu alebo nekonzistentnostiam. V týchto kontextoch je zvyčajne lepšie držať sa sekvenčného prístupu alebo použiť podrobnejší a kontrolovanejší paralelizmus.
Ďalšie možnosti paralelného spustenia v PowerShelle
Plus ForEach-Object -Parallel, PowerShell ponúka niekoľko spôsobov paralelnej práceV starších verziách aj vo vetve 7.x. Každá z nich má svoje výhody a nevýhody a je dôležité ich poznať, aby ste si vybrali správny nástroj.
Start-Job: úlohy v nezávislých procesoch
Rutina cmdlet Start-Job Existuje vo všetkých verziách PowerShellu a spúšťa sa pracujú v samostatných procesoch, každý s vlastnou inštanciou PowerShelluToto poskytuje silnú izoláciu, ale má to veľa režijných nákladov: vytváranie nových procesov, serializácia a deserializácia objektov späť atď.
V mnohých scenároch môže dôjsť k sekvenčnej slučke rýchlejšie ako zneužívanie Start-Jobnajmä ak sú úlohy krátke alebo vracajú veľké množstvo zložitých údajov. Okrem toho Start-Job štandardne nezahŕňa a ThrottleLimitPreto si musíte sami riadiť, koľko úloh beží súčasne.
Start-ThreadJob: úlohy založené na vláknach
Modul ThreadJob poskytuje cmdlet Start-ThreadJobktorý používa priestory runspace na vytvorenie ľahšie pracovné miesta ako tie v Start-JobZdieľaním procesu sa zabráni mnohým stratám typových informácií spôsobeným serializáciou medzi procesmi.
V PowerShell 7 a novších verziách je modul ThreadJob už zahrnutý, zatiaľ čo v Windows PowerShell 5.1 je možné nainštalovať z galérie PowerShell. Start-ThreadJob podporuje parameter ThrottleLimitTo vám umožňuje kontrolovať, koľko z týchto úloh sa spúšťa naraz, čím sa zabráni vyčerpaniu systémových zdrojov.
Spustené priestory PowerShell a SDK
V pokročilých scenároch môžete pracovať priamo s menným priestorom System.Management.Automation.Runspaces z PowerShell SDK. To vám umožňuje vytvoriť si vlastnú veľmi jemnú logiku paralelizmu, ktorá riadi správu behových priestorov, poolov, synchronizácie atď. V skutočnosti oboje ForEach-Object -Parallel ako Start-ThreadJob Interne sa spoliehajú na bežiace priestory.
Tento prístup ponúka maximálna flexibilita a potenciálny výkonTo však tiež znamená väčšiu zložitosť a „prepracovanosť“ kódu. V mnohých prípadoch vstavané cmdlety (ForEach-Object -Parallel a Start-ThreadJob) pokrývajú väčšinu potrieb, čím eliminujú potrebu takýchto zložitostí.
Pracovné postupy a foreach -Parallel v prostredí Windows PowerShell
Windows PowerShell 5.1 mal funkciu Pracovné postupyŠpeciálny typ skriptu určený pre dlhotrvajúce úlohy s možnosťou pozastavenia, obnovenia a paralelného spustenia. V rámci pracovného postupu by sa konštrukt mohol použiť foreach -ParallelŽe spustiť blok skriptu raz pre každý prvok v kolekcii súčasne.
Základná syntax foreach -Parallel je to niečo ako foreach -Parallel ($item in $collection) { ... }A Platí len v rámci pracovného postupu.Prvky kolekcie sa spracovávajú paralelne, zatiaľ čo príkazy v rámci bloku sa vykonávajú postupne pre každý prvok (hoci sa dajú kombinovať aj s blokmi) parallel { ... } interné).
Pracovné postupy však Nie sú dostupné v PowerShell 7 alebo novších verziách.Taktiež sa neodporúčajú pre nový vývoj. Napriek tomu je užitočné pochopiť syntax a koncept, ak udržiavate staršie skripty, ktoré ich používajú. foreach -Parallel, pretože jeho správanie sa líši od normálneho foreach aj ForEach-Object -Parallel.
Obmedzenie súbežnosti s ThrottleLimit
Skutočnosť, že niečo môže bežať paralelne, neznamená, že to bude rýchlejšie. V skutočnosti môžu byť aplikácie veľmi náročné na I/O alebo ľahké skripty pomalšie. Výkon sa stratí, ak je súčasne vykonávaných príliš veľa úloh.či už kvôli preťaženiu CPU, disku, siete alebo jednoducho kvôli záťaži správy toľkých vlákien naraz.
Aby sa tento aspekt vyvážil, Start-ThreadJob y ForEach-Object -Parallel Ponúkajú parameter ThrottleLimitToto nastavuje maximálny počet úloh alebo iterácií, ktoré je možné spustiť naraz. Ak sa pokúsite spustiť viac úloh, ako je povolené, budú zaradené do frontu, kým sa jedna z nich nedokončí a neuvoľní miesto.
Od verzie PowerShellu 7.1, ForEach-Object -Parallel opätovne používa priestory runspace z predvoleného fondua hodnota ThrottleLimit určuje veľkosť daného fondu. Predvolená hodnota je 5, čo je zvyčajne dobrý východiskový bod. Existuje aj modifikátor na vytvorenie nového behu pre každú iteráciu (UseNewRunspace), ale oplatí sa to iba vtedy, keď potrebujete veľmi silnú izoláciu a akceptujete väčšie preťaženie.
Na druhej strane cmdlet Start-Job chýba ThrottleLimitPreto, ak to neovládate manuálne, môžete skončiť s desiatkami alebo stovkami procesov PowerShellu spustených súčasne, čo má zodpovedajúci vplyv na výkon a pamäť.
Meranie výkonnosti rôznych prístupov
Rozumný spôsob, ako sa rozhodnúť, ktorý model paralelizmu použiť, je Zmerajte skutočné časy vykonávania pre váš prípad použitiaNa to môžete použiť funkciu ako Measure-Parallel, ktorý porovnáva rýchlosť niekoľkých prístupov: Start-Job, Start-ThreadJob, ForEach-Object -Parallel y Start-Process.
Táto funkcia vytvára simulovanú kolekciu vstupov (napr. názvy ZIP súborov), generuje niekoľko „dávok“ alebo pracovných relácií a pre každý prístup meria, ako dlho trvá spracovanie daného počtu prvkov s... veľkosť dávky nakonfigurovaná používateľom BatchSize a celkovo prác JobCountTaktiež prispôsobuje dostupné prístupy v závislosti od verzie PowerShellu a prítomnosti alebo neprítomnosti Start-ThreadJob.
vnútri, Measure-Parallel nakonfigurovať spustiteľný súbor (napríklad cmd.exe o shso zoznamom argumentov a definuje hašovaciu tabuľku s implementáciami špecifickými pre každý prístup. Measure-Command vypočítajte celkový čas Spracovaním všetkých dávok pre každú alternatívu vám to umožní zobraziť podrobné správy s -Verbose A nakoniec vráti objekt so súhrnom časov, aby sa dali ľahko porovnať.
Spúšťanie niečoho ako Measure-Parallel -Approach All -BatchSize 5 -JobCount 20 -Verbose Na počítači so systémom Windows a PowerShellom 7.5.1 sa v tomto konkrétnom prípade pozorovalo, Start-Process získať najkratší častesne nasledovaný ForEach-Object -Parallel y Start-ThreadJobKým Start-Job Ukazuje sa, že je to najpomalšia možnosť kvôli veľkej réžii spojenej so spúšťaním podradených procesov PowerShellu.
Paralelizmus a „tradičné“ cykly foreach
V praxi sa často stáva, že pri migrácii starších pracovných postupov a skriptov do PowerShellu 7 začnete nahradiť manuálne runspace, moduly tretích strán, ako napríklad PoshRSJob alebo Workflows prostredníctvom už integrovaných nástrojov, ako napríklad Start-ThreadJob y ForEach-Object -ParallelToto zjednodušuje kód a znižuje počet externých závislostí. Je tiež bežné integrovať automatizačné riešenia, ako napríklad PowerShell DSC.
Niektorí administrátori, ktorí používali manuálne fondy behu, začali mať nestabilné správanie (napríklad skripty sa v produkčných prostrediach náhodne ukončovali) a keďže čelili ťažkostiam s ladením týchto problémov, rozhodli sa pre... znížiť zložitosť a spoľahnúť sa na integrované paralelné funkcie ktoré sú už testované a podporované samotným tímom PowerShellu.
Pokročilé techniky s foreach: vnorenie, filtrovanie a spracovanie chýb
Okrem paralelizmu, slučky foreach vám umožňuje vytvoriť veľmi bohatú logiku keď spojíte vety if, vnorenie slučiek a spracovanie výnimiek.
V rámci a foreach Je bežné používať kondicionály if spracovať prvky odlišne na základe ich vlastností. Napríklad iterácia cez všetky súbory v adresári a spracovanie iba tých, ktoré presahujú určitú veľkosť, ich kopírovanie na iné miesto, ich kompresia alebo ich vymazanie, ak spĺňajú určité požiadavky na vek.
Môžete tiež vnorovať slučky foreach pre generovať kombinácie prvkov z niekoľkých kolekciíNapríklad zoznamy testovacích parametrov, karteziánske súčiny čísel a písmen alebo dvojrozmerné prechody dát. V tomto prípade je nevyhnutné nepoužívať rovnaký názov premennej vo vnútornej a vonkajšej slučke, aby sa predišlo zámene a jemným chybám.
Pokiaľ ide o spracovanie chýb, ak a foreach narazí na neošetrenú výnimku, Je možné, že sa celý skript zastaví.čo nie je vždy žiaduce. Obvyklý spôsob posilnenia slučky je zabaliť vnútornú logiku do bloku. try { ... } catch { ... }Takže, ak sa niečo pokazí s konkrétnou položkou, môžete chybu zaznamenať a pokračovať so zvyškom kolekcie bez zastavenia celého vykonávania.
Bežné chyby a osvedčené postupy s foreach
Pri práci s slučky foreach v PowerShelleJedným z týchto problémov je používanie rovnakého názvu premennej vo vnorených slučkách, čo spôsobuje, že vnútorná hodnota prepíše vonkajšiu a generuje nepredvídateľné výsledky. Riešenie je jednoduché: pre každú úroveň vnorenia použite rôzne názvy.
Ďalšou častou chybou je zneužívať break bez premýšľaniaTo spôsobí, že slučka sa ukončí pred spracovaním celej kolekcie, pričom zámerom bolo jednoducho preskočiť určité prvky. V mnohých prípadoch continue Je to vhodnejšie, pretože umožňuje preskočiť konkrétne iterácie bez úplného opustenia slučky.
Tiež si treba dávať pozor na nekonečné slučky, najmä keď sa upraví tá istá prechádzaná kolekciaAk pridávame prvky do toho istého poľa bez akejkoľvek kontroly počas iterácie, ľahko sa dostaneme do slučky, ktorá sa nikdy neskončí. Veľmi užitočnou technikou je iterovať cez kópiu pôvodnej kolekcie a vykonať potrebné úpravy v „skutočnej“ verzii.
Pokiaľ ide o všeobecné osvedčené postupy, zvyčajne sa odporúča použitie ForEach-Object pre dáta prichádzajúce cez kanál, pričom telo slučky musí byť čo najčitateľnejšie pomocou pomocných funkcií a telo skriptu musí byť konzistentne odsadené a komentáre sa musia v priebehu času používať.
Zvládnutie rôznych variantov foreach a ich možností paralelizmu v PowerShelle, od ForEach-Object -Parallel y Start-ThreadJob dokonca aj starí ľudia foreach -Parallel V pracovných postupoch vám to umožňuje navrhovať oveľa rýchlejšie a robustnejšie skripty, pričom si v každom prípade vyberiete, či máte záujem uprednostniť výkon, pamäť, poradie výstupu alebo jednoduchosť kódu, namiesto toho, aby ste sa vždy obmedzovali na tradičnú sekvenčnú slučku.
Vášnivý spisovateľ o svete bajtov a technológií všeobecne. Milujem zdieľanie svojich vedomostí prostredníctvom písania, a to je to, čo urobím v tomto blogu, ukážem vám všetko najzaujímavejšie o gadgetoch, softvéri, hardvéri, technologických trendoch a ďalších. Mojím cieľom je pomôcť vám orientovať sa v digitálnom svete jednoduchým a zábavným spôsobom.