Powershell v2.0使用多个线程 [英] Powershell v2.0 Using multiple threads

查看:73
本文介绍了Powershell v2.0使用多个线程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

基本脚本构想: 你好.我创建了一个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中没有像omp parallel这样的东西吗? :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."

我在这里找到使用的代码: 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


}

解决方案

您可以在后台作业中运行循环的每次迭代,该作业不同于单独的线程,因为它是一个完整的其他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的运行空间问题

您也许可以用 OpenReadAsync 代替DownloadFileAsync

Basic script idea: Hello. I've created a powershell script which I use to check the filesizes of certain executables, and then keep them in a text file. Next time the script runs, if a filesize differs it will replace the one in the text file with the new one.

The structure: I have a main script and a folder which contains many scripts, each for every executable of which I want to check the filesize. So the scripts in the folder will return a string containing the link to the executable, which will be fed to the main script.

The code:

$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 {
    ...

Question: This for loop is the one I want to run in parallel. I need your advice on how to do this since I'm new to powershell. I tried to implement a few things I found but they didn't work correctly (took very long to finish, output errors, multiple entries of filesizes in my filesizes file). I suspect it's a synchronization issue and somehow I need to lock the critical parts. Isn't there anything like omp parallel for in powershell? :P

Any help,advice on how to achieve this would be appreciated :)

edit:

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."

Edit 2: Used code I found here: 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


}

解决方案

You can run each iteration of the loop in a background job which is not the same a seperate thread in that it is a whole other PowerShell.exe process. Data is passed from the background processes through serialization.

To approach it using background jobs you'll need to define a script block that will do that actual work and then call the script block with parameters in each iteration of the loop. The script block can report back status via Write-Output or by throwing an exception.

You'll probably want to throttle how many concurrent background jobs are running. Here's an example of how to throttle:

$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

As an alternative you might try eventing. Take a look at this thread for some examples of how to implement concurrency using events.

PowerShell: Runspace problem with DownloadFileAsync

You might be able to replace DownloadFileAsync with OpenReadAsync

这篇关于Powershell v2.0使用多个线程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆