[英]Decreased output with PowerShell multithreading than with singlethread script
我在Windows 7桌面上使用PowerShell 2.0。 我正在嘗試在企業CIFS共享中搜索關鍵字/正則表達式。 我已經有一個簡單的單線程腳本可以執行此操作,但是單個關鍵字需要19-22個小時。 根據Surly Admin的文章,我創建了一個多線程腳本,首先致力於多線程。
以及與這些帖子相關的鏈接。
我決定使用運行空間而不是后台作業,因為普遍的觀點認為這樣做效率更高。 問題是,使用我擁有的多線程腳本,我只會得到部分結果輸出。 不知道這是I / O還是內存還是其他東西。 希望這里有人可以提供幫助。 這是代碼。
cls
Get-Date
Remove-Item C:\Users\user\Desktop\results.txt
$Throttle = 5 #threads
$ScriptBlock = {
Param (
$File
)
$KeywordInfo = Select-String -pattern KEYWORD -AllMatches -InputObject $File
$KeywordOut = New-Object PSObject -Property @{
Matches = $KeywordInfo.Matches
Path = $KeywordInfo.Path
}
Return $KeywordOut
}
$RunspacePool = [RunspaceFactory]::CreateRunspacePool(1, $Throttle)
$RunspacePool.Open()
$Jobs = @()
$Files = Get-ChildItem -recurse -erroraction silentlycontinue
ForEach ($File in $Files) {
$Job = [powershell]::Create().AddScript($ScriptBlock).AddArgument($File)
$Job.RunspacePool = $RunspacePool
$Jobs += New-Object PSObject -Property @{
File = $File
Pipe = $Job
Result = $Job.BeginInvoke()
}
}
Write-Host "Waiting.." -NoNewline
Do {
Write-Host "." -NoNewline
Start-Sleep -Seconds 1
} While ( $Jobs.Result.IsCompleted -contains $false)
Write-Host "All jobs completed!"
$Results = @()
ForEach ($Job in $Jobs) {
$Results += $Job.Pipe.EndInvoke($Job.Result)
$Job.Pipe.EndInvoke($Job.Result) | Where {$_.Path} | Format-List | Out-File -FilePath C:\Users\user\Desktop\results.txt -Append -Encoding UTF8 -Width 512
}
Invoke-Item C:\Users\user\Desktop\results.txt
Get-Date
這是我正在使用的單線程版本,包括我用於社交的正則表達式。
cls
Get-Date
Remove-Item C:\Users\user\Desktop\results.txt
$files = Get-ChildItem -recurse -erroraction silentlycontinue
ForEach ($file in $files) {
Select-String -pattern '[sS][sS][nN]:*\s*\d{3}-*\d{2}-*\d{4}' -AllMatches -InputObject $file | Select-Object matches, path |
Format-List | Out-File -FilePath C:\Users\user\Desktop\results.tx -Append -Encoding UTF8 -Width 512
}
Get-Date
Invoke-Item C:\Users\user\Desktop\results.txt
我希望隨着時間的推移建立這個答案,因為我不想過多評論。 我還不知道為什么您會從多線程中丟失數據,但是我認為我們可以通過更新的正則表達式來提高性能。 首先,您有許多貪婪的量詞,我認為我們可以縮小。
[sS][sS][nN]:*\\s*\\d{3}-*\\d{2}-*\\d{4}
選擇字符串默認情況下不區分大小寫,因此您不需要在開頭部分。 您是否需要檢查多個冒號? 由於您尋找0或許多:
。 連字符也一樣。 也許這些會更好? 匹配0或1。
ssn:?\\s*\\d{3}-?\\d{2}-?\\d{4}
這是假設您正在尋找大多數格式正確的SSN。 如果人們將它們隱藏在文本中,則可能還需要尋找其他定界符。
我還建議將文本添加到單獨的文件中,或者在執行后將它們合並。 如果沒有別的只是測試。
希望這將是適當解決方案的開始。
事實證明,由於某些原因,Select-String cmdlet遇到了多線程問題。 我沒有足夠的開發人員背景,無法告訴您幕后發生的事情。 但是,我確實發現通過使用Select-String中的-quiet選項將其轉換為布爾輸出,我能夠獲得所需的結果。
每個文檔中的第一個模式匹配都給出一個真實值。 當得到true時,我將文檔的Path返回到數組。 完成后,我對腳本塊輸出的路徑運行模式匹配。 這並不是我所希望的那樣有效的性能,但是與單線程相比仍然是相當顯着的改進。
我遇到的另一個問題是通過嘗試在每個階段將結果輸出到文檔來對磁盤進行讀/寫。 我已經將其更改為數組。 雖然仍然占用大量內存,但是速度要快得多。
這是結果代碼。 任何其他有關提高性能的技巧都值得贊賞:
cls
Remove-Item C:\Users\user\Desktop\output.txt
$Throttle = 5 #threads
$ScriptBlock = {
Param (
$File
)
$Match = Select-String -pattern 'ssn:?\s*\d{3}-?\d{2}-?\d{4}' -Quiet -InputObject $File
if ( $Match -eq $true ) {
$MatchObjects = Select-Object -InputObject $File
$MatchOut = New-Object PSObject -Property @{
Path = $MatchObjects.FullName
}
}
Return $MatchOut
}
$RunspacePool = [RunspaceFactory]::CreateRunspacePool(1, $Throttle)
$RunspacePool.Open()
$Jobs = @()
$Files = Get-ChildItem -Path I:\ -recurse -erroraction silentlycontinue
ForEach ($File in $Files) {
$Job = [powershell]::Create().AddScript($ScriptBlock).AddArgument($File)
$Job.RunspacePool = $RunspacePool
$Jobs += New-Object PSObject -Property @{
File = $File
Pipe = $Job
Result = $Job.BeginInvoke()
}
}
$Results = @()
ForEach ($Job in $Jobs) {
$Results += $Job.Pipe.EndInvoke($Job.Result)
}
$PathValue = @()
ForEach ($Line in $Results) {
$PathValue += $Line.psobject.properties | % {$_.Value}
}
$UniqValues = $PathValue | sort | Get-Unique
$Output = ForEach ( $Path in $UniqValues ) {
Select-String -Pattern '\d{3}-?\d{2}-?\d{4}' -AllMatches -Path $Path | Select-Object -Property Matches, Path
}
$Output | Out-File -FilePath C:\Users\user\Desktop\output.txt -Append -Encoding UTF8 -Width 512
Invoke-Item C:\Users\user\Desktop\output.txt
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.