我可以创建 PSJob 并重新运行现有作业而不创建新作业吗?作业的创建花费了太长的时间并且减慢了脚本的速度。
Start-Job -Name Mytest -ScriptBlock {get-service}
Receive-job -Name Mytest -wait
# Rerun MyTest
我对其他想法持开放态度
我的目标是: 1) 脚本必须驻留在内存中,因为从磁盘读取速度太慢。 2) 输出必须返回到控制台。我不想将结果写入磁盘。 3) 该脚本必须独立于启动它的脚本。 PSRunSpaces 连接到启动它的脚本,因此它们不是一个选项。 4)我坚持使用 PS 5.1,但是,如果高版本有选项,我会听。 5)操作系统是Server 2019。
编辑1:脚本可以通过输入参数加载到内存中吗?我只想同时运行脚本的一份副本。该脚本必须保留输出,直到像 PSjobs 一样请求为止。使用互斥体是可以的。我可能说错了,但是,我正在寻找 powershell 中存在的独立工作线程。
以下内容可能更多的是学术练习,而不是现实生活中有用的东西,因为它依赖于
Start-ThreadJob
cmdlet,它提供了一个轻量级、更快的基于 thread 的替代方案,替代基于子进程的常规方案使用 Start-Job
创建的后台作业,也保留了类型保真度:考虑到此类作业的轻量级以及创建它们的速度,为每个后台任务创建一个新作业 - 而不是维护后台任务所属的 single 作业授权 - 可能就足够了。
Start-ThreadJob
附带 PowerShell (Core) 7+,在 Windows PowerShell 中可以根据需要安装,例如 Install-Module ThreadJob -Scope CurrentUser
。
Start-Job
实例实现下面的代码是可能的,但需要复杂的IPC机制来通信工作项,或者指定的临时文件;无论哪种方式,都必须使用 PowerShell 的 CLIXML 序列化,这总是需要从调用者传递的值和从作业返回的结果的类型保真度有限。
以下代码:
定义函数
Get-WorkerJob
,该函数返回一个自定义对象,其中包含线程作业(.Job
属性)和同步队列(.Queue
属性),该作业在轮询循环中监视工作项并按顺序进行处理。
调用者可以以带有
ScriptBlock
条目的哈希表的形式添加工作项 - 如果必须传递来自调用者的值 - ArgumentList
条目 - 请注意,不支持 $using:
引用。
Receive-Job
收集结果,并最终使用 Receive-Job
-Force
清理作业(可以实现一种更优雅的方式来关闭工人作业)
# Function that creates a thread-based worker job, using Start-ThreadJob.
function Get-WorkerJob {
# Create a synchronized queue.
$workerQueue = [System.Collections.Queue]::Synchronized([System.Collections.Queue]::new())
# Construct and output a custom object containing the queue
# and a thread job that processes the queue.
[pscustomobject] @{
Job = Start-ThreadJob {
$workerQueue = $using:workerQueue
$workItem = $null
do {
while ($workerQueue.Count -gt 0 -and $(try { ($workItem = $workerQueue.Dequeue()) } catch {})) {
# [Console]::WriteLine('got one: ' + $workItem.ScriptBlock)
# To avoid cross-thread issues, the script block must be rebuilt.
# The challenge is that $using references are not supported in local
# script-block invocation. Hence only passing *arguments* is supported.
& $workItem.ScriptBlock.Ast.GetScriptBlock() $workItem.ArgumentList
}
# Queue is empty, sleep a little before checking for new work items.
Start-Sleep -Milliseconds 500
} while ($true)
}
Queue = $workerQueue
}
}
# -- Sample use of the function above.
# Create a thread-based worker job
$worker = Get-WorkerJob
# Pass two sample work items, one without and one with values from the caller.
@{ ScriptBlock = { Get-Date } },
@{ ScriptBlock = { Get-Date -Date $args[0] }; ArgumentList = '1/1/1970' } |
ForEach-Object {
# Send a work item to the worker job.
$worker.Queue.Enqueue($_)
Start-Sleep 1
# Receive, consume, and output the results (so far)
$worker.Job | Receive-Job
}
# Remove the worker job.
$worker.Job | Remove-Job -Force