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