3

基本的なスクリプトのアイデア:こんにちは。特定の実行可能ファイルのファイルサイズを確認し、それらをテキストファイルに保存するために使用するPowerShellスクリプトを作成しました。次回スクリプトを実行するときに、ファイルサイズが異なる場合は、テキストファイル内のファイルサイズが新しいファイルサイズに置き換えられます。

構造:メインスクリプトと、ファイルサイズを確認したい実行可能ファイルごとに多くのスクリプトを含むフォルダーがあります。したがって、フォルダ内のスクリプトは、実行可能ファイルへのリンクを含む文字列を返します。この文字列は、メインスクリプトに送られます。

コード:

$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を初めて使用するので、これを行う方法についてアドバイスが必要です。見つけたいくつかのことを実装しようとしましたが、正しく機能しませんでした(終了するのに非常に長い時間がかかり、エラーが出力され、filesizesファイルにfilesizesの複数のエントリがありました)。同期の問題だと思います。どういうわけか、重要な部分をロックする必要があります。PowerShellにompparallelのようなものはありませんか?: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


}
4

1 に答える 1

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:DownloadFileAsyncの実行スペースの問題

DownloadFileAsyncをOpenReadAsyncに置き換えることができる場合があります

于 2012-04-16T19:38:17.940 に答える