2012-04-16 61 views
3

基本腳本構想: 你好。我創建了一個powershell腳本,用於檢查某些可執行文件的文件大小,然後將它們保存在文本文件中。下次腳本運行時,如果文件大小不同,它將用新文件替換文本文件中的文件大小。Powershell v2.0使用多線程

結構: 我有一個主腳本和一個文件夾,其中包含許多腳本,每個腳本都需要檢查每個可執行文件的大小。因此,文件夾中的腳本將返回一個包含可執行文件鏈接的字符串,該鏈接將被提供給主腳本。

代碼:

$progdir = "C:\script\programms" 
$items = Get-ChildItem -filter *.ps1 -Path $progdir 
$webclient = New-Object System.Net.WebClient 

$filesizes = get-content C:\updatechecker\programms\filesizes 
if ($filesizes.length -ne $items.length) { 
    if ($filesizes.length -eq $null) { 
     Write-Host ("Building filesize database...") -nonewline 
    } 
    else { 
     Write-Host ("Rebuilding filesize database...") -nonewline 
    } 
    clear-content C:\programms\filesizes 

    for ($i=0; $i -le $items.length-1; $i++) { 
     $command = "c:\programms\" + $items[$i].name 
     $link = & $command 
     $webclient.OpenRead($link) | Out-Null 
     $filesize = $webclient.ResponseHeaders["Content-Length"] 
     $filesize >> C:\programms\filesizes 
    } 
    echo "Done." 
} 
else { 
    ... 

問: 這for循環是一個我想並行運行。我需要你的建議,因爲我剛剛接觸PowerShell。我試圖實現一些我發現的東西,但它們不能正常工作(花了很長時間才完成,輸出錯誤,在文件大小文件中有多個文件大小的條目)。我懷疑這是一個同步問題,不知何故我需要鎖定關鍵部分。在PowerShell中沒有像omp並行的東西嗎? :P

任何幫助,如何實現這一建議,將不勝感激:)

編輯:

Get-Job | Remove-Job -Force 
$progdir = "C:\programms" 
$items = Get-ChildItem -filter *.ps1 -Path $progdir 
$webclient = New-Object System.Net.WebClient 
$filesizes = get-content C:\programms\filesizes 

$jobWork = { 
    param ($MyInput) 
    $command = "c:\programms\" + $MyInput 
    $link = & $command 
    $webclient.OpenRead($link) | Out-Null 
    $filesize = $webclient.ResponseHeaders["Content-Length"] 
    $filesize >> C:\programms\filesizes 

} 
foreach ($item in $items) { 

    Start-Job -ScriptBlock $jobWork -ArgumentList $item.name | out-null 
} 

Get-Job | Wait-Job 
Get-Job | Receive-Job | Out-GridView | out-null 
echo "Done." 

編輯2:使用的代碼,我發現在這裏:http://ryan.witschger.net/?p=22

$mutex = new-object -TypeName System.Threading.Mutex -ArgumentList $false, 「RandomGlobalMutexName」; 
$MaxThreads = 4 
$SleepTimer = 500 


$jobWork = { 
    param ($MyInput) 
    $webclient = New-Object System.Net.WebClient 
    $command = "c:\programms\" + $MyInput 
    $link = & $command 
    $webclient.OpenRead($link) | Out-Null 

    $result = $mutex.WaitOne(); 

    $file = $webclient.ResponseHeaders["Content-Length"] 
    $file >> C:\programms\filesizes 

    $mutex.ReleaseMutex(); 
} 

$progdir = "C:\programms" 
$items = Get-ChildItem -filter *.ps1 -Path $progdir 
$webclient = New-Object System.Net.WebClient 
$filesizes = get-content C:\programms\filesizes 

Get-Job | Remove-Job -Force 

$i = 0 

ForEach ($item in $items){ 
    While ($(Get-Job -state running).count -ge $MaxThreads){ 

     Start-Sleep -Milliseconds $SleepTimer 
    } 

    $i++ 
    Start-Job -ScriptBlock $jobWork -ArgumentList $item.name | Out-Null 


} 

回答

3

您可以在後臺作業中運行循環的每次迭代,這不同於單獨的線程,因爲它是整個其他PowerShell.exe進程。數據通過序列化從後臺進程傳遞。

要使用後臺作業來處理它,您需要定義一個腳本塊來完成實際工作,然後在循環的每次迭代中使用參數調用腳本塊。腳本塊可以通過Write-Output或通過拋出異常來報告返回狀態。

您可能想要調節正在運行的併發背景作業的數量。下面是一個如何節流的例子:

$jobItems = "a", "b", "c", "d", "e" 
$jobMax = 2 
$jobs = @() 

$jobWork = { 
    param ($MyInput) 
    if ($MyInput -eq "d") { 
     throw "an example of an error" 
    } else { 
     write-output "Processed $MyInput" 
    } 
} 

foreach ($jobItem in $jobItems) { 
    if ($jobs.Count -le $jobMax) { 
     $jobs += Start-Job -ScriptBlock $jobWork -ArgumentList $jobItem 
    } else { 
     $jobs | Wait-Job -Any 
    } 
} 
$jobs | Wait-Job 

作爲一種替代方案,您可以嘗試事件。看看這個線程中的一些關於如何使用事件實現併發的例子。

PowerShell: Runspace problem with DownloadFileAsync

您也許能OpenReadAsync

+0

謝謝安迪更換DownloadFileAsync。我之前嘗試的是創建一個腳本,它將使用Start-Job將我的$ items數組傳遞給主腳本。雖然這影響了我的整個腳本,而不僅僅是for循環迭代,因此無法按照我的預期工作。我會嘗試你的建議(使用相同的腳本調用腳本塊,而不是從單獨的腳本調用整個腳本文件),然後回覆給你。 – kokotas 2012-04-16 20:43:13

+0

我嘗試了你建議的安迪,但沒有奏效。我的文件上沒有寫入任何內容。但它改變$ filesize >> C:\ programms \ filesizes爲 「something」>> C:\ programms \ filesizes,然後我可以看到一些行(東西)會被寫入,這個數字等於$ jobMax變量我設置。我認爲這是鎖定關鍵部件的問題......我應該提到被調用來返回鏈接的腳本,它們不僅返回「http:// ....」,而且還寫入一個對所有鏈接都通用的文件。一旦完成,下一個將覆蓋文件等。 – kokotas 2012-04-16 21:37:22

+0

@kokotas沒有看你的代碼我不知道你需要什麼。但是請確保通過Start-Job上的-ArgumentList參數將數據傳遞給腳本塊。您將無法在腳本塊外設置的腳本塊中使用變量。 – 2012-04-17 00:57:02