對應 30天挑戰精通 PowerShell 該書第 14 章「利用背景作業進行多工處理」。
PowerShell 透過背景執行功能,以非同步方式運行多個命令,來滿足多工處理( multitasking )的需求。
PowerShell 會以同步( synchronous )的方式執行普通的命令,這表示當你按下 Enter 鍵之後,必須等待該命令完全執行完畢。而將一項工作移至背景,可以讓它以非同步( asynchronous )的方式執行,這表示你在命令執行完成的過程中,同時還能繼續使用 shell 進行其他工作。
命令按順序執行,當前命令完成後才執行下一個命令。這可能導致等待時間過長。
命令在後台執行,腳本不必等待命令完成就可以繼續執行其他接續的 command or script,這提高了效率和響應性。
PowerShell 本身是一個單線程應用程序(a single-threaded application),特別是在 PowerShell 5.1 及更早版本中,它默認情況下以單線程運行。這意味著,PowerShell 的大多數命令都是同步執行的,即執行一個命令必須等待它完成後,才能繼續執行下一個命令。從 PowerShell 7 開始,新增了對多線程的更好支持,包括 Start-ThreadJob
和 ForEach-Object -Parallel
等功能,使其可以更高效地執行多任務處理。
處理程序作業(Process Job)是在獨立的 PowerShell 進程中運行的作業。這種作業與主會話隔離,不共享變量或環境。
Start-Job
要開始一個 Process Job,需要使用 Start-Job
命令,以下是書中有提到針對該指令的細節:
-ScriptBlock
:指定要執行的命令(或多個命令)。-Name
:指定一個自訂的作業名稱。-FilePath
:透過背景執行一個包含多個命令的指令碼檔案-WorkingDirectory
:允許你變更作業在檔案系統的開始位置,應使用絕對路徑( absolute path )。透過 Receive-Job 搭配 Job Id 以取得該 Job 執行結果。
透過 &
將指令透過背景執行。
執行緒作業(Thread Job)是在同一 Process 內的不同 Thread 中運行。
start-threadJob
透過 start-threadJob
執行後的輸出結果與 start-job
的輸出結果很相似,差異之處只有兩個
這告訴我們,該作業是在「目前使用的處理程序」內執行,但在「不同的執行緒」中。
觀察一下 Job 間的 Id 變化,第一個 Job1 的 Id 是 1,而第二個 Job3 的 Id 卻是 2,書中有提到是因為每個作業至少會有一個子作業( child job ),以 Job 1 為例,它裡面包含了 Job2( Job 1 的子作業 )。
通過將所有作業(無論是本地的還是遠程的)都表示為具有父子關係的結構,PowerShell 能夠提供一致的接口和命令來管理它們。這使得用戶可以使用相同的命令(如 Get-Job、Receive-Job 等)來處理不同類型的作業。
一些作業可能會非常複雜,涉及多個子任務。例如,使用 Invoke-Command 在多台遠程計算機上執行命令時,每個目標計算機上的命令執行都是一個子作業。父作業充當容器,管理和跟蹤所有子作業。
父作業可以匯總所有子作業的狀態和結果,方便用戶查看整體執行情況。這對於需要監控和管理多個併發任務的場景非常有用。
透過建立子作業表格,再搭配列表內的子作業名稱或 ID 以取得該子作業的結果。
> get-job -id 1 | Select-object -expand childjobs
PowerShell 7.0 引入了 ForEach-Object 的 -Parallel 參數,能夠在管道中並行處理數據。這對於需要對大量對象執行相同操作的場景非常有用,可以顯著提高腳本的性能。
$collection | ForEach-Object -Parallel {
# script
} -ThrottleLimit <最大並行數>
$collection
:目標集合。-Parallel
:指示 ForEach-Object 在並行模式下運行。-ThrottleLimit
:可選參数,指定同时運行的最大線程数。默認值為 5。假設有一系列文件需要處理,例如將每個文件複製到另一個目錄。使用 ForEach-Object -Parallel,並可以同時處理多個文件:
$sourceFiles = Get-ChildItem -Path "C:\SourceFolder"
$sourceFiles | ForEach-Object -Parallel {
Copy-Item -Path $_.FullName -Destination "C:\DestinationFolder\"
} -ThrottleLimit 10
當需要對多個 API 端點發送請求時,可以利用並行處理加快速度:
$urls = @(
"https://api.example.com/data1",
"https://api.example.com/data2",
"https://api.example.com/data3"
)
$results = $urls | ForEach-Object -Parallel {
Invoke-RestMethod -Uri $_
} -ThrottleLimit 5
Day 17 - 逐一處理多個物件