PowerShell / PowerShell/PowerShell
`ForEach-Object -Parallel`: consider changing the semantics of the `-TimeoutSeconds` parameter to apply to each thread or provide a new switch / parameter that does
還沒有人認領這個 Issue。
- 主要語言
- C#
- 星號
- 55.5k
- 分支
- 8.5k
- 平均合併
- 1 天 2 小時
- 30 天內合併 PR
- 88
描述
Summary of the new feature / enhancement
The current semantics of the -TimeoutSeconds parameter are arguably unhelpful:
-
The
-TimeoutSecondsinterval is applied to the runtime duration of the overall, typically throttled and therefore "batched" invocation[1] rather than to the runtime of each thread.- Therefore, a timeout can occur even if each individual thread completed in less than the specified timeout. A simple example:
# This times out when the 3rd thread runs, because - due to ThrottleLimit 2 -
# it only starts after 1.5+ seconds, after the first 2 threads
# have finished.
1..4 |
ForEach-Object -TimeoutSeconds 2 -ThrottleLimit 2 -Parallel {
Start-Sleep -MilliSeconds 1500
$_ # Pass the input object through.
}
-
When a timeout occurs, the command terminates overall.
- This means that threads for any remaining pipeline input then never even get to launch.
- In the above example, only
1and2print; input4never gets processed, because processing of3caused the timeout and therefore termination of the entire command.
- In the above example, only
- This means that threads for any remaining pipeline input then never even get to launch.
Applying the specified timeout:
- on a per-thread basis...
- ... and continuing processing of the inputs even if a single thread times out
is arguably much more sensible.
Therefore, I suggest implementing the latter:
-
Either: By simply changing the meaning of the current
-TimeoutSecondsparameter, assuming it amounts to a bucket 3 change. -
Or: By introducing a separate parameter / additional switch parameter as an opt-in to the proposed semantics.
[1] More accurately, only a fixed number of threads are allowed to run at a time, based on the -ThrottleLimit arguments, which defaults to 5. If more threads are needed, they have to wait until "slots" open up, which happens when currently executing threads finish.
Proposed technical implementation details (optional)
The following shows the desired semantics expressed in PowerShell code, applied to a slightly modified version of the example above, which provokes a timeout for the 3rd input object:
# Use -AsJob to receive a job that allows monitoring the threads individually.
# Note that -AsJob cannot be combined with -TimeoutSeconds
$job =
1..4 |
ForEach-Object -AsJob -ThrottleLimit 2 -Parallel {
if ($_ -eq 3) {
# Provoke a timeout error for this specific input.
Start-Sleep -MilliSeconds 2500; $_
} else {
Start-Sleep -MilliSeconds 1500; $_
}
}
# Receive job output in a polling loop, and terminate child jobs
# that have run too long.
$timeout = 2
do {
Start-Sleep -Milliseconds 500 # Sleep a little.
# Get pending results.
$job | Receive-Job
# If any child jobs have been running for more than N seconds,
# stop (terminate) them.
# This will open up slots for more threads to spin up.
foreach ($childJob in $job.ChildJobs.Where({ $_.State -eq 'Running' })) {
if (([datetime]::now - $childJob.PSBeginTime).TotalSeconds -ge $timeout) {
Write-Verbose -Verbose "Stopping job with ID $($childJob.Id) due to running longer than $timeout seconds..."
$childJob | Stop-Job
}
}
} while ($job.ChildJobs.Where({ $_.State -in 'NotStarted', 'Running' }))
Output:
1
2
4
VERBOSE: Stopping job with ID 4 due to running longer than 2 seconds...
Note:
-
Input
4was still processed, despite the thread for input3having timed out. -
The
IDvalue of the child job isn't really meaningful except to distinguish it from other child jobs; if you want to know what input object caused the timeout, you'll have to echo it as part of the script block (at the start, before a timeout can occur) - the job object doesn't contain this information.
貢獻指南
從這裡開始
- 先讀完整個 Issue,再讀專案的貢獻指南。
- 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
- Fork 儲存庫,在一個分支上完成修改。
- 送出 Pull Request,並在描述裡引用這個 Issue 編號。
研究方向
首先,使用 -TimeoutSeconds、-ThrottleLimit 和 -AsJob 重現 ForEach-Object -Parallel 範例。比較目前的整體逾時行為與提議的每執行緒行為,包括其中一個執行緒逾時後繼續處理的情況。當現有參數具有新的語意,或由有文件說明的 opt-in 參數提供這些語意,並涵蓋受節流控制的輸入與已逾時的執行緒時,即視為完成。
由索引模型根據 Issue 內容生成。
評估
- 技術堆疊
- powershell
- 領域
- cli
- Issue 類型
- 功能
- 難度
- 5/5
- 預估耗時
- 一週以上
- 活躍度
- 停滯
- 描述清晰度
- 基本清楚
- 新手友好度
- 35/100