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 新手,因此我需要您对如何执行此操作的建议。我尝试实现我发现的一些东西,但它们无法正常工作(完成时间很长,输出错误,我的文件大小文件中的多个文件大小条目)。我怀疑这是一个同步问题,不知何故我需要锁定关键部分。powershell中没有类似omp parallel for的东西吗?: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 回答