Powershell作业可提高状态行的性能

时间:2019-04-19 21:19:25

标签: c# windows performance powershell terminal

我正在研究自定义的Powershell状态行,并实现了一些很酷的功能:电池监视,WiFi监视等。不幸的是,这些更新往往很慢,因为它们需要调用Get-NetAdapterStatistics,获取wmi对象,和其他非常慢的电话。我正在尝试通过start-job生成子进程,以允许进行后台轮询和更新共享变量,但无法弄清楚该怎么做。我发现最好的替代方法是某种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会话将挂起无法进行ctrl-c操作的位置。

谢谢,请告诉我是否可以添加更多信息。

更新:我尝试使用空文件基本上作为控制标志(我认为这比为每个设置解析一个文件要快),但是我试图使用作业来返回VCS信息(这样做更容易返回,速度更快)。关于如何解决此问题的任何想法?我很沮丧

注意:我标记了此C#,因为powershell使用C#的管道函数,并且希望有相关知识的人能够提供帮助。

1 个答案:

答案 0 :(得分: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        ...