注意:我試圖
packer.exe作為后臺行程運行以解決azure-arm構建器的特定問題,我需要觀察輸出。我沒有使用,Start-Process因為我不想使用中間檔案來使用輸出。
我將以下代碼設定packer.exe為在后臺運行,以便我可以使用其輸出并根據特定日志訊息采取行動。這是更大腳本的一部分,但這是有問題的部分行為不正確:
$builderDir = ( Split-Path -Parent $PSCommandPath )
Push-Location $builderDir
# Set up the packer command to run asynchronously
$pStartProps = @{
FileName = ( Get-Command -CommandType Application packer ).Source
Arguments = "build -var-file ""${builderDir}\win-dev.pkrvars.hcl"" -only ""azure-arm.base"" ."
UseShellExecute = $false
RedirectStandardOutput = $true
RedirectStandardError = $false
LoadUserProfile = $true
}
$pStartInfo = New-Object ProcessStartInfo -Property $pStartProps
$p = [Process]::Start($pStartInfo)
while ( $null -ne ( $output = $p.StandardOutput.Readline() ) -or !$p.HasExited ) {
# Do stuff
}
基本上,條件的( $output = $p.StandardOutput.Readline() )一部分while似乎會掛起,直到有更多的輸出要讀取。我不確定這是為什么,因為StreamReader.Readline() 應該回傳要讀取的下一行,或者null如果沒有更多輸出。關于我期望獲得的日志訊息,我對此進行了相當多的處理,因此在沒有進一步輸出消耗時讀取 STDOUT 時阻塞會使腳本無用。它在packer.exe繼續執行的同時還在前臺做其他事情。
我能夠在Readline()確實讀取空行(值"")的除錯器中確認,這似乎發生在還沒有進一步輸出要消耗的時候。這可能是相切的,但這也會導致除錯器出錯。
發生此問題時,VSCode 除錯器會$output = $p.StandardOutput.Readline()高亮顯示幾秒鐘,然后除錯器停止(一切都消失了,沒有更多的變數跟蹤等),直到Readline()停止阻塞并繼續執行,此時除錯器似乎重新初始化跟蹤的變數、監視的運算式等。因此,發生這種情況時我根本無法使用除錯器。即使PowerShell Integrated Console(與除錯器一起使用的)掛起,我也無法輸入任何內容。
對于完整的背景關系,這個腳本的目標是讓packer.exe我繼續回圈執行它的事情:
- 顯示更多輸出
packer.exe - 檢查特定日志訊息的存在
- 花
packer.exe一點時間嘗試自己做它需要做的事情 - If it waits too long, I execute a script against the node being since what
packer.exeshould have done on its own likely failed- I am using
Invoke-AzVMRunCommandto do this, which can't be done at the statepacker.exefor the issue I am working around. It must be performed out-of-band of thepacker.exerun itself.
- I am using
- The build continues on after the workaround is applied and I simply continue forwarding the output of
packer.exeto the console until the process exits
But since the script hangs when there is no output, step 4 will never work as I have to give packer time to try to complete the config on its own, and is the entire reason why I'm hacking this together in the first place.
Why is Readline() blocking here? Am I doing something incorrectly? This behavior occurs whether I run my script in Windows PowerShell or PowerShell Core.
uj5u.com熱心網友回復:
StreamReader.ReadLine()按設計阻止。有一個異步替代方法 ,
.ReadLineAsync()它回傳一個Task<string>實體,您可以通過其屬性輪詢完成,.IsCompleted而不會阻塞前臺執行緒(輪詢是您在 PowerShell 中的唯一選項,因為它沒有類似于 C# 的語言功能await)。
這是一個簡化的示例,重點是從StreamReader恰好是一個檔案的實體中進行異步讀取,新行僅定期添加到該檔案中;用于Ctrl-C中止。
如果您將其調整為標準輸出讀取System.Diagnostics.Process代碼,我希望代碼能夠正常作業。
# Create a sample input file.
$n=3
1..$n > tmp.txt
# Open the file for reading, and convert it to a System.IO.StreamReader instance.
[IO.StreamReader] $reader =
[IO.File]::Open("$pwd/tmp.txt", 'Open', 'Read', 'ReadWrite')
try {
$task = $reader.ReadLineAsync() # Start waiting for the first line.
while ($true) { # Loop indefinitely to wait for new lines.
if ($task.IsCompleted) { # A new line has been received.
$task.Result # Output
# Start waiting for the next line.
$task.Dispose(); $task = $reader.ReadLineAsync();
}
else { # No new line available yet, do other things.
Write-Host '.' -NoNewline
Start-Sleep 1
}
# Append a new line to the sample file every once in a while.
if ( $n % 10 -eq 0) { $n >> tmp.txt }
}
}
finally {
$reader.Dispose()
}
uj5u.com熱心網友回復:
在StreamReader從流-從標準輸出等待IOStandardOutput不能得到用于讀,直到它得到更多的資料或Process關閉。StreamReader在 TCP 流上使用也存在類似的問題,您可以享受等待網路流量的樂趣。
在通常圍繞它的辦法就是讓不同的任務等待就可以通過異步讀取像ReadLineAsync()。這對您的while回圈沒有幫助,因為它在繼續讀取輸出的StreamReader.
如果packer.exe的輸出表現良好,您可以嘗試使用 powershell 作業的輸出屬性而不是[process]? 我用ping它進行了測驗,給出了相同的等待 IO 鎖定行為:
# Locks up for full ping timeout example:
$pStartProps = @{ FileName = 'ping.exe' ; Arguments = '10.bad.ip.0' ... }
$p = [System.Diagnostics.Process]::Start($pStartInfo)
# Locks when reading
$output = $p.StandardOutput.ReadLine()
while ( $output -ne $null ) {
$output = $p.StandardOutput.ReadLine(); ## read the output
# Do stuff
}
#####
# Does not lock when using Job output instead:
$job = Start-Job -ScriptBlock { ping.exe 10.bad.ip.0 }
While ($job.State -ne 'Completed') {
$job.ChildJobs[0].Output ## read the output
# Do stuff
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/327899.html
標籤:.net powershell .net-core powershell-core
上一篇:如何在C#.netcore3.1中的MVC控制器中傳遞json變數
下一篇:是否可以使用dotnetnew創建一個ASP.NETWebApplicationEmpty.NetFramework4.7.2專案?
