基本脚本的想法: 你好。我创建了一个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并行的东西? :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
}
答案 0 :(得分: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
替换DownloadFileAsync