Runspacepool работает, но блокирует интерфейс

У меня есть 13 папок в моем тестовом пространстве. Открывая диспетчер задач, я вижу, что потоки Java (не более 5 одновременно! Из-за настройки min, max) работают, а затем завершаются. Есть журнал вывода для каждого потока пространства выполнения, так что я знаю, что он перебирает все выбранные местоположения.

Даже если большую часть этого кода он похитил с Boe Prox, все работает отлично, за исключением того, что он блокирует окно Xaml до тех пор, пока не будет закрыто пространство пробега.

Поскольку для этого требуется инструмент Java, которым вы не обладаете, я надеюсь, что структура покажет ошибку.

Есть элементы этого пользовательского интерфейса, которые я планирую удалить, так что если они не называются, то это по замыслу.

Add-Type -Path 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\PresentationFramework\v4.0_4.0.0.0__31bf3856ad364e35\PresentationFramework.dll'

$syncHash = [hashtable]::Synchronized(@{})
$newRunspace =[runspacefactory]::CreateRunspace()
$newRunspace.ApartmentState = "STA"
$newRunspace.ThreadOptions = "ReuseThread"
$newRunspace.Open()
$newRunspace.SessionStateProxy.SetVariable("syncHash",$syncHash)

$syncHash.Host = $host

# Load WPF assembly

$psCmd = [PowerShell]::Create().AddScript({
[xml]$xaml = @'
<Window 
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        Title="Verify" MinHeight="350" Height="350" Width="379" >
    <Border Padding="10">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="1*" />
                    <ColumnDefinition Width="2*" />
                    <ColumnDefinition Width="1*" />
                    <ColumnDefinition Width="2*" />
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition Height="30" />
                    <RowDefinition Height="25" />
                    <RowDefinition Height="25" />
                    <RowDefinition Height="*" />
                    <RowDefinition Height="10" />
                    <RowDefinition Height="20" />
                    <RowDefinition Height="15" />
                    <RowDefinition Height="25" />
                </Grid.RowDefinitions>
                <Label Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="4" FontSize="14" VerticalContentAlignment="Top" HorizontalAlignment="Center" >Select Study(s)</Label>
                <Label Name="lblXMS" Grid.Row="1" Grid.Column="0" HorizontalAlignment="Center" Padding="0,5">Xms</Label>
                <TextBox Name="XMSBox" Grid.Row="1"  Grid.Column="1" Width="30" Height="20" HorizontalAlignment="Left" Padding="1,1">16
                    <ToolTipService.ToolTip >
                        <ToolTip Content="Xms sets the initial size of the Java heap."   
                                HorizontalOffset="5" VerticalOffset="5"/>
                    </ToolTipService.ToolTip>
                </TextBox>
                <Label Name="lblXMX" Grid.Row="1" Grid.Column="2" HorizontalAlignment="Center" Padding="0,5">Xmx</Label>
                <TextBox Name="XMXBox" Grid.Row="1"  Grid.Column="3" Width="30" Height="20" HorizontalAlignment="Left" Padding="1,1">32
                    <ToolTipService.ToolTip >
                        <ToolTip Content="Xmx sets the maximum size of the Java heap."   
                                HorizontalOffset="5" VerticalOffset="5"/>
                    </ToolTipService.ToolTip>
                </TextBox>
                <CheckBox Name="CheckBox" Grid.Column="1" Grid.Row="2" HorizontalAlignment="Center" VerticalAlignment="Center" />
                <Label Grid.Column="2" Grid.ColumnSpan="2" Grid.Row="2" HorizontalAlignment="Left" VerticalAlignment="Center">Parallel?</Label>
                <ListBox Name="ListBox" SelectionMode="Extended" Grid.Row="3" Grid.ColumnSpan="2" MinHeight="125" Grid.Column="0" ScrollViewer.VerticalScrollBarVisibility="Auto" />
                <TextBox Name="Output" TextWrapping="Wrap" Grid.Row="3" Grid.ColumnSpan="2" MinHeight="125" Grid.Column="2" ScrollViewer.VerticalScrollBarVisibility="Auto" />
                <Button Name="Verify" IsEnabled="False" Grid.Row="7" Grid.ColumnSpan="4" HorizontalAlignment="Center" Grid.Column="0" Width="82" >Verify</Button>
            </Grid>
    </Border>
</Window>
'@

    $reader=(New-Object System.Xml.XmlNodeReader $xaml)
    $syncHash.Window=[Windows.Markup.XamlReader]::Load( $reader )
    [xml]$XAML = $xaml
    $xaml.SelectNodes("//*[@*[contains(translate(name(.),'n','N'),'Name')]]") | ForEach-Object{
        $syncHash.Add($_.Name,$syncHash.Window.FindName($_.Name) )
        }

    $Script:JobCleanup = [hashtable]::Synchronized(@{})
    $Script:Jobs = [system.collections.arraylist]::Synchronized((New-Object System.Collections.ArrayList))

    $jobCleanup.Flag = $True
    $newRunspace =[runspacefactory]::CreateRunspace()
    $newRunspace.ApartmentState = "STA"
    $newRunspace.ThreadOptions = "ReuseThread"
    $newRunspace.Open()
    $newRunspace.SessionStateProxy.SetVariable("jobCleanup",$jobCleanup)
    $newRunspace.SessionStateProxy.SetVariable("jobs",$jobs)
    $jobCleanup.PowerShell = [PowerShell]::Create().AddScript({

    #Routine to handle completed runspaces
        Do{
            Foreach($runspace in $jobs)
            {
                If ($runspace.Runspace.isCompleted)
                {
                    $null = $runspace.powershell.EndInvoke($runspace.Runspace)
                    $runspace.powershell.dispose()
                    $null = $runspace.Runspace
                    $null = $runspace.powershell
                }
            }

            #Clean out unused runspace jobs
            $temphash = $jobs.clone()
            $temphash | Where{
                $_.runspace -eq $Null
                } | ForEach{
                    $jobs.remove($_)
                    }
            Start-Sleep -Seconds 1
        } while ($jobCleanup.Flag)
    })

    $jobCleanup.PowerShell.Runspace = $newRunspace
    $jobCleanup.Thread = $jobCleanup.PowerShell.BeginInvoke()


    $syncHash.Window.Add_Loaded({

        $syncHash.Output.Clear();
        $syncHash.ListBox.Items.Clear();

        $getC = Get-ChildItem C:\Projects -Directory | Where-Object{
            $_.Name -match '^[0-9]{5,6}[a-zA-Z]?$' 
            }

        $Drivelett = [System.IO.DriveInfo]::GetDrives() | Where-Object{ 
            $_.DriveType -ne "Network" -and $_.DriveType -ne "CDRom" -and $_.DriveType -ne "DVDRom" -and $_.Name -ne "E:\" -and $_.Name -ne "C:\" -and $_.Name -match '^[a-zA-Z]{1}:\\$' 
            }

        $redac = $Drivelett -replace ':\\',''

        $AllElse = Get-PSDrive -Name $redac | Get-PSDrive | ForEach-Object{
            Set-Location $_.Root -ErrorAction Ignore;
                get-childitem -Directory | Where-Object{ 
                    $_.Name -match '^[0-9]{5,6}[a-zA-Z]?$' 
                    }
        }

        $totalstudy = $GetC+$AllElse | Sort

        foreach ($T in $totalstudy)
        {
            $null = $syncHash.ListBox.Items.Add($T.FullName)
        }
   })

    $syncHash.ListBox.Add_SelectionChanged({
        if ($(($syncHash.ListBox.SelectedItems).count) -gt 0){
            $syncHash.Verify.IsEnabled = $True
            }
        Else {
            $syncHash.Verify.IsEnabled = $False
            }
    })

    function Start-VerifyRS ($Rows){

        # Create an empty array that we'll use later
        $RunspaceCollection = @()
        $newRunspace.SessionStateProxy.SetVariable("SyncHash",$global:synchash)
        # This is the array we want to ultimately add our information to
        [Collections.Arraylist]$qwinstaResults = @()

        # Create a Runspace Pool with a minimum and maximum number of run spaces. (http://msdn.microsoft.com/en-us/library/windows/desktop/dd324626(v=vs.85).aspx)
        $RunspacePool = [RunspaceFactory]::CreateRunspacePool(1,5)

        # Open the RunspacePool so we can use it
        $RunspacePool.Open()

        # Define a script block to actually do the work
        $ScriptBlock = {
            Param($Row)
            $queryResults = java.exe "-Xms16M" "-Xmx32M" -jar C:\verify.jar $( $Row[0] ) $( $Row[1] ) C:\verify.properties >C:\Projects\Logs\$( $Row[1] )\$( $Row[2] )_Verify.log
            $queryResults
        } #/ScriptBlock

        # Create PowerShell objects, then for each one add the unique computer name.
        Foreach ($Row in $Rows) {
            # Create a PowerShell object to run add the script and argument.
            # We first create a Powershell object to use, and simualtaneously add our script block we made earlier, and add our arguement that we created earlier
            $Powershell = [PowerShell]::Create().AddScript($ScriptBlock).AddArgument($Row).AddArgument($syncHash)

            # Specify runspace to use
            # This is what let's us run concurrent and simualtaneous sessions
            $Powershell.RunspacePool = $RunspacePool

            # Create Runspace collection
            # When we create the collection, we also define that each Runspace should begin running
            [Collections.Arraylist]$RunspaceCollection += New-Object -TypeName PSObject -Property @{
                Runspace = $PowerShell.BeginInvoke()
                PowerShell = $PowerShell  
            } #/New-Object
        } #/ForEach

        # Now we need to wait for everything to finish running, and when it does go collect our results and cleanup our run spaces
        # We just say that so long as we have anything in our RunspacePool to keep doing work. This works since we clean up each runspace as it completes.
        While($RunspaceCollection) {

            # Just a simple ForEach loop for each Runspace to get resolved
            Foreach ($Runspace in $RunspaceCollection.ToArray()) {

                # Here's where we actually check if the Runspace has completed
                If ($Runspace.Runspace.IsCompleted) {

                    # Since it's completed, we get our results here
                    $null = $qwinstaResults.Add($Runspace.PowerShell.EndInvoke($Runspace.Runspace))

                    # Here's where we cleanup our Runspace
                    $Runspace.PowerShell.Dispose()
                    $RunspaceCollection.Remove($Runspace)

                } #/If
            } #/ForEach
        } #/While

        $syncHash.Window.Dispatcher.invoke([action]{$syncHash.Output.AppendText("`nThe Results of qwinstaResults is ... `n")},"Background")
        $syncHash.Window.Dispatcher.invoke([action]{$syncHash.Output.AppendText("$qwinstaResults")},"Background")
        $syncHash.Window.Dispatcher.invoke([action]{$syncHash.Output.AppendText((""))},"Background")
    }

    $syncHash.Verify.Add_Click({

        $syncHash.Output.Clear()

        $Projects = @()
        $Projects = $syncHash.ListBox.SelectedItems

        $dt = New-Object System.Data.Datatable
        $null = $dt.Columns.Add("Projects")
        $null = $dt.Columns.Add("Segments")
        $null = $dt.Columns.Add("Repsplit")

        foreach ($P in $Projects)
        {
            $null = $dt.Rows.Add(('{0}' -f $P),('{0}' -f (split-path -Path $P -Leaf)),('{0}' -f ($P -replace ':\\','_' -replace '\\','_')))
        }                

        $syncHash.Window.Dispatcher.invoke([action]{$syncHash.Output.AppendText("`$dt.Projects = `r`n{0}`r`n" -f "$(foreach($dtPr in $($dt).Projects){"$dtPr`r`n"})")},"Background")
        $syncHash.Window.Dispatcher.invoke([action]{$syncHash.Output.AppendText("`$dt.RepSplit = `r`n{0}`r`n" -f "$(foreach($dtRe in $($dt).RepSplit){"$dtRe`r`n"})")},"Background")
        $syncHash.Window.Dispatcher.invoke([action]{$syncHash.Output.AppendText("`$dt.Segments = `r`n{0}`r`n" -f "$(foreach($dtSe in $($dt).Segments){"$dtSe`r`n"})")},"Background")

        foreach ( $seg in $($dt | select -ExpandProperty Segments -Unique ) )
        {
            if ( !( Test-Path -path "C:\Projects\Cache_Logs\$seg" ) )
            {
                $null = New-Item "C:\Projects\cache_logs\$seg" -type directory
            }
        }

        $Rows = $dt.Rows                

        Start-VerifyRS $Rows

        $syncHash.Window.Dispatcher.invoke([action]{$syncHash.Output.AppendText(($Error))},"Normal")
    })

    #region Window Close
    $syncHash.Window.Add_Closed({
        Write-Verbose 'Halt runspace cleanup job processing'
        $jobCleanup.Flag = $False

        #Stop all runspaces
        $jobCleanup.PowerShell.Dispose()
    })

    $null = $syncHash.Window.ShowDialog()
    $syncHash.Error = $Error
    $Error
})

$psCmd.Runspace = $newRunspace
$data = $psCmd.BeginInvoke()
$Error

0 ответов

Другие вопросы по тегам