2012-04-16 56 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