iT邦幫忙

2024 iThome 鐵人賽

DAY 16
0

對應 30天挑戰精通 PowerShell 該書第 14 章「利用背景作業進行多工處理」。

PowerShell 透過背景執行功能,以非同步方式運行多個命令,來滿足多工處理( multitasking )的需求。


同步 vs. 非同步

PowerShell 會以同步( synchronous )的方式執行普通的命令,這表示當你按下 Enter 鍵之後,必須等待該命令完全執行完畢。而將一項工作移至背景,可以讓它以非同步( asynchronous )的方式執行,這表示你在命令執行完成的過程中,同時還能繼續使用 shell 進行其他工作。

同步( Synchronous )

命令按順序執行,當前命令完成後才執行下一個命令。這可能導致等待時間過長。

非同步(Asynchronous)

命令在後台執行,腳本不必等待命令完成就可以繼續執行其他接續的 command or script,這提高了效率和響應性。

關鍵差異

  • 執行同步命令時,遺漏了必要參數,PowerShell 會提示你輸入遺漏的資訊,非同步去執行時,命令會直接顯示執行失敗。
  • 同步命令執行完後預設會將結果顯示出來,而非同步命令則是必須等到命令執行完畢後,再去取得快取起來的結果( the cached results )。

讓 PowerShell 同時執行多項任務

PowerShell 本身是一個單線程應用程序(a single-threaded application),特別是在 PowerShell 5.1 及更早版本中,它默認情況下以單線程運行。這意味著,PowerShell 的大多數命令都是同步執行的,即執行一個命令必須等待它完成後,才能繼續執行下一個命令。從 PowerShell 7 開始,新增了對多線程的更好支持,包括 Start-ThreadJobForEach-Object -Parallel 等功能,使其可以更高效地執行多任務處理。


建立一個處理程序作業

處理程序作業(Process Job)是在獨立的 PowerShell 進程中運行的作業。這種作業與主會話隔離,不共享變量或環境。

Start-Job

要開始一個 Process Job,需要使用 Start-Job 命令,以下是書中有提到針對該指令的細節:

  • -ScriptBlock :指定要執行的命令(或多個命令)。
  • -Name :指定一個自訂的作業名稱。
  • -FilePath :透過背景執行一個包含多個命令的指令碼檔案
  • -WorkingDirectory :允許你變更作業在檔案系統的開始位置,應使用絕對路徑( absolute path )。

Example 1: Start a background job

透過 Receive-Job 搭配 Job Id 以取得該 Job 執行結果。
https://ithelp.ithome.com.tw/upload/images/20240930/20168708AGJyXVNHhE.png

Example 2: Use the background operator to start a background job

透過 & 將指令透過背景執行。
https://ithelp.ithome.com.tw/upload/images/20240930/20168708BmYR5dpm56.png


建立一個執行緒作業

執行緒作業(Thread Job)是在同一 Process 內的不同 Thread 中運行。

start-threadJob

https://ithelp.ithome.com.tw/upload/images/20240930/20168708e6wBvbcB2k.png
透過 start-threadJob 執行後的輸出結果與 start-job 的輸出結果很相似,差異之處只有兩個

  • PSJobTypeName
  • Location

這告訴我們,該作業是在「目前使用的處理程序」內執行,但在「不同的執行緒」中。

建議

  • 由於啟動一個新執行緒的速度遠快於新的處理程序,因此「執行緒作業」非常適合那些需要快速啟動且在背景中執行的短時間指令碼和命令。
  • 一個處理程序只能執行一定數量的執行緒,過多的話會開始變慢,PowerShell 內部設定了一個「節流限制」,協助你防止 PowerShell 過度負荷。

子作業

觀察一下 Job 間的 Id 變化,第一個 Job1 的 Id 是 1,而第二個 Job3 的 Id 卻是 2,書中有提到是因為每個作業至少會有一個子作業( child job ),以 Job 1 為例,它裡面包含了 Job2( Job 1 的子作業 )。
https://ithelp.ithome.com.tw/upload/images/20240930/20168708yTikwizVAQ.png
https://ithelp.ithome.com.tw/upload/images/20240930/201687083AosUPBnAe.png
https://ithelp.ithome.com.tw/upload/images/20240930/201687080oSflqSEW7.png

存在的目的

統一的作業模型

通過將所有作業(無論是本地的還是遠程的)都表示為具有父子關係的結構,PowerShell 能夠提供一致的接口和命令來管理它們。這使得用戶可以使用相同的命令(如 Get-Job、Receive-Job 等)來處理不同類型的作業。

擴展性和複雜性管理

一些作業可能會非常複雜,涉及多個子任務。例如,使用 Invoke-Command 在多台遠程計算機上執行命令時,每個目標計算機上的命令執行都是一個子作業。父作業充當容器,管理和跟蹤所有子作業。

狀態和結果的聚合

父作業可以匯總所有子作業的狀態和結果,方便用戶查看整體執行情況。這對於需要監控和管理多個併發任務的場景非常有用。

當一個作業有多個子作業時

透過建立子作業表格,再搭配列表內的子作業名稱或 ID 以取得該子作業的結果。

> get-job -id 1 | Select-object -expand childjobs

使用 ForEach-Object -Parallel 進行並行處理

PowerShell 7.0 引入了 ForEach-Object 的 -Parallel 參數,能夠在管道中並行處理數據。這對於需要對大量對象執行相同操作的場景非常有用,可以顯著提高腳本的性能。

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 - 逐一處理多個物件


上一篇
Day 15 - 解釋 WinRM、PSSession、Invoke-Command
下一篇
Day 17 - 逐一處理多個物件
系列文
《30天挑戰精通 PowerShell:從 Windows Server 到 Azure DevOps 自動化之旅》30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言