Задания Powershell для повышения производительности строки состояния - PullRequest
0 голосов
/ 20 апреля 2019

Я работаю над пользовательской строкой состояния PowerShell и реализовал несколько интересных функций: мониторинг батареи, мониторинг Wi-Fi и т. Д. К сожалению, они, как правило, обновляются медленно, так как требуют вызовов Get-NetAdapterStatistics, получения объектов wmi, и другие очень медленные звонки. Я пытаюсь порождать дочерние процессы с помощью start-job, чтобы обеспечить фоновый опрос и обновление общей переменной, но не могу понять, как это сделать. Лучшая возможная замена, которую я нашел, - это своего рода IPC (как описано здесь: Конвейер между двумя процессами SEPARATE Powershell ), но я бы предпочел придерживаться традиционной разделяемой переменной, если это возможно. Есть ли способ сделать это? Лучшая альтернатива, которую я нашел, это передача переменных в качестве аргументов, но это не позволяет проводить опрос.

К слову, я знаю, что это не совсем то, для чего предназначен 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()

Самым большим недостатком этого является то, что это немного глючно. Самое главное, я не знаю, как закрыть канал IPC, когда я закрываю окно powershell (так как это строка состояния), и в результате я получаю «утечку канала», которая приводит к высокой загрузке процессора и процессам powershell, выполняющимся в фон. По крайней мере, это не относится к прямой фоновой работе, записывающей в файл. Очевидно, что канал должен закрываться при удалении последней ссылки, но фоновое задание продолжает работать с ним открытым. Это связано с тем, что сеанс powershell будет зависать до такой степени, что его нельзя будет нажать ctrl-c, когда он ожидает чего-то связанного с каналом (при ожидании соединения с каналом, для завершения записи строки и т. Д.).

Спасибо, и, пожалуйста, дайте мне знать, если я смогу добавить больше информации.

Обновление: я пытался использовать пустые файлы в основном в качестве контрольных флагов (я думаю, это было бы быстрее, чем анализ одного файла для каждого параметра), но я пытаюсь использовать задание для возврата информации VCS (что было бы проще просто возвращайся и быстрее). Есть идеи, как решить эту проблему? Я в тупике.

Примечание: я пометил этот C #, потому что powershell использует конвейерные функции C #, и я надеюсь, что кто-то со знанием этого сможет помочь.

1 Ответ

0 голосов
/ 22 апреля 2019

Boe Prox выполнил отличную запись за эти годы назад.Он также расширил это с помощью модуля 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        ...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...