Powershell工作可以提高状态线性能

问题描述 投票:0回答:1

我正在开发一个自定义的PowerShell状态线,并实现了一些很酷的功能:电池监控,wifi监控等等。不幸的是,这些更新往往很慢,因为它们需要调用Get-NetAdapterStatistics,获取wmi对象等等。慢叫。我试图通过启动作业生成子进程以允许后台轮询和更新共享变量,但无法弄清楚如何执行此操作。我找到的最好的替代品是一种IPC(如这里所描述的:Pipelining between two SEPARATE Powershell processes),但如果可能的话,我更愿意坚持使用传统的共享变量。有没有办法做到这一点?我发现的最好的替代方法是将变量作为参数传递,但这不允许轮询。

为了放弃,我知道这并不是PowerShell的设计目标,但我仍然想知道这是否可行。或者是编写将返回状态行的c / c ++二进制文件的最佳选择?写入文件(这似乎可能很慢)?如果您能够,或者您需要更多信息,请告诉我可能有用的内容。谢谢。

更多信息:

Start-Job -Name testJob -Script {
        $testVar = "asdf"
}

Write-Host $testVar
# should output asdf

有没有办法做到这一点?我正在尝试做一些工作并返回一个变量。这怎么可能?我发现的唯一可行方法是:

  1. 写一个文件到磁盘,这有点慢
  2. 使用IPC管道:
$pipe = New-Object System.IO.Pipes.NamedPipeClientStream '.',"testPipe",'In'
Start-Job -Name testJob -Script {
        $pipe = New-Object System.IO.Pipes.NamedPipeServerStream "testPipe",'Out'
        $pipe.WaitForConnection()
        $sw = New-Object System.IO.StreamWriter $pipe
        $sw.AutoFlush = $true
        $sw.writeLine("foo")
        While ($true) {
                # do looping and polling, then print stuff
                $sw.writeLine($pollResult)
        }
        $sw.Dispose()
        $pipe.Dispose()
}

$pipe.Connect()
$sr = New-Object System.IO.StreamReader $pipe
#when necessary, read info
$output = $sr.ReadLine()
$sr.Dispose()
$pipe.Dispose()

最大的缺点是它有点小问题。最重要的是,当我关闭powershell窗口时,我不知道如何关闭IPC管道(因为这是一个状态线),我最终导致“管道泄漏”导致高CPU使用率和PowerShell进程运行的背景。这至少不是直接后台作业写入文件的情况。显然,管道应该在删除最后一个引用时关闭,但后台作业在打开时继续运行。这是因为当PowerShell会等待与管道相关的事情(等待管道连接,完成写入线路等)时,powershell会话将挂起到无法ctrl-c'd的程度。

谢谢,如果我可以添加更多信息,请告诉我。

更新:我已经尝试使用空文件作为控制标志(我认为它比为每个设置解析一个文件更快),但我正在尝试使用作业返回VCS信息(这将更容易返回,并且快点)。关于如何解决这个问题的任何想法?我很难过。

注意:我标记了这个C#,因为powershell使用C#的管道功能,我希望有知识的人可以提供帮助。

c# windows performance powershell terminal
1个回答
0
投票

Boe Prox在几年前做了一个excellent writeup。他还用PoshRSJob模块扩展了它。使用此模块可以很容易地处理。

#Create a synchronized hashtable
$sync = [hashtable]::Synchronized(@{
    Time = ''
    Stop = $false
    Updater = ''
})
#create 5 RSJobs
1..5 | Start-RSJob -ScriptBlock {
    param($sync) #accept $sync as a param
    $updater = [Guid]::NewGuid() #unique id per job
    while(-not $sync.Stop) { #run until told not to
        $sync.Time = Get-Date
        $sync.Updater = $updater
        start-sleep -Seconds 1
    }
} -ArgumentList $sync #pass $sync as a param

运行这会产生5个工作:

Id       Name                 State           HasMoreData  HasErrors    Command
--       ----                 -----           -----------  ---------    -------
1        Job1                 Running         False        False        ...
2        Job2                 Running         False        False        ...
3        Job3                 Running         False        False        ...
4        Job4                 Running         False        False        ...
5        Job5                 Running         False        False        ...

然后,您可以检查父进程中的$ sync,并看到它是从这些作业不断更新的。请注意,这些不仅仅是字符串表示,而是完整的成熟对象。

PS C:\> $sync

Name     Value
----     -----
Time     4/22/2019 11:58:35 AM
Stop     False
Updater  9ab28c51-2941-4866-a064-165b1ceca673

PS C:\> $sync

Name     Value
----     -----
Time     4/22/2019 11:58:37 AM
Stop     False
Updater  113e78a8-1774-4cdf-9638-7235109f0a0d

要终止工作,我们设置$sync.Stop = $true

PS C:\> Get-RSJob

Id       Name                 State           HasMoreData  HasErrors    Command
--       ----                 -----           -----------  ---------    -------
1        Job1                 Completed       False        False        ...
2        Job2                 Completed       False        False        ...
3        Job3                 Completed       False        False        ...
4        Job4                 Completed       False        False        ...
5        Job5                 Completed       False        False        ...
© www.soinside.com 2019 - 2024. All rights reserved.