1

私はスピードのために完全にマルチスレッドのスクリプトを作成しようとしていますが、私が書いた同期バージョンは動作しますが遅いです。私は、各スレッドがExchangeセッション情報をインポートしているので、特にサーバー数が増えるにつれて同期コードよりも遅いか遅いという壁を打ちました。同じExchangeセッション状態情報を複数回実行プールで使用するにはどうすればよいですか?

もっと良い方法があると確信しています。これを行う適切な方法は、pssessionを一度読み込んでそれをrunspaceプールに追加することですが、私の検索では、 Exchangeでこれを行うには?

以下は私の非同期対同期比較です。非同期コードの実行時間は12:41で、同期コードの実行時間は15:02でした。

cls 
$stopWatch = [System.Diagnostics.Stopwatch]::StartNew(); 
[DateTime]::Now.ToString(); 




    # Fill in these two values 
$connectionUri = "http://[something]/powershell"; 
$servers = @("server1","server2","server3","server4","server5","server6","server7","server8","server9","server10","server11","server12"); 
    # /fill 




# asynchronous 
Write-Host "Asynchronous"; 

# Create session state 

$myString = "this is session state!"; 
$sessionState = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault(); 
$sessionstate.Variables.Add((New-Object -TypeName System.Management.Automation.Runspaces.SessionStateVariableEntry -ArgumentList "myString" ,$myString, "example string")); 

# Create runspace pool consisting of $numThreads runspaces 
$minimumAmountOfThreads = 1; 
$maximumAmountOfThreads= 15; 
$RunspacePool = [RunspaceFactory]::CreateRunspacePool($minimumAmountOfThreads, $maximumAmountOfThreads, $sessionState, $Host); 
$RunspacePool.Open(); 


$threads = @(); 
$Jobs = @(); 
$asynchronousThreadCount = 0; 
[int]$index = 0; 
foreach ($server in $servers) 
{ 
    $scriptBlock = "import-pssession (new-pssession -ConfigurationName Microsoft.Exchange -ConnectionUri $connectionUri) -AllowClobber; `$returnValue = @(); `$returnValue += Get-ExchangeServer -Identity $server; `$returnValue += Get-MailboxDatabase -Server $server; `$returnValue += Get-MailboxDatabase -Server $server -status; return `$returnValue;"; # working 

    $asynchronousThreadCount ++; 
    $runspaceObject = [PSCustomObject] @{ 
     Runspace = [PowerShell]::Create() 
     Invoker = $null 
    } 
    $runspaceObject.Runspace.RunSpacePool = $runspacePool; 
    $runspaceObject.Runspace.AddScript($scriptBlock) | Out-Null; 
    $runspaceObject.Runspace.AddArgument($server) | Out-Null; 
    $runspaceObject.Invoker = $runspaceObject.Runspace.BeginInvoke(); 
    $threads += $runspaceObject; 
    $elapsed = $StopWatch.Elapsed; 

    Write-Host "Asynchronous created thread $asynchronousThreadCount " $elapsed; 
    $index++; 
} 

Write-Host $threads.Count; 
Write-Host ""; 
Write-Host "Waiting.." -NoNewline; 
Do { 
    Write-Host "." -NoNewline; 
    Start-Sleep -Seconds 1; 
} While ($runspaceObject.Invoker.IsCompleted -contains $false); 

$resultsAsynchronous = @(); 

foreach ($tr in $threads) 
{ 
    $resultsAsynchronous += $tr.Runspace.EndInvoke($tr.Invoker); 
    $tr.Runspace.Dispose(); 
} 

$runspacePool.Close(); 
$runspacePool.Dispose();  

$elapsed = $StopWatch.Elapsed; 
Write-Host ""; 
Write-Host "Multithread elapsed time: $elapsed"; 
Write-Host "Asynchronous return value count " $resultsAsynchronous.Count; 

Write-Host ""; 
Write-Host ""; 
Write-Host ""; 







# synchronous 
Write-Host "Synchronous"; 

$StopWatch.Reset | Out-Null; 
import-pssession (new-pssession -ConfigurationName Microsoft.Exchange -ConnectionUri $connectionUri) -AllowClobber; 
$resultsSynchronous = @(); 
foreach ($server in $servers) 
{ 
    $resultsSynchronous += Get-ExchangeServer -Identity $server; 
    $resultsSynchronous += Get-MailboxDatabase -Server $server; 
    $resultsSynchronous += Get-MailboxDatabase -Server $server -status; 
} 

$elapsed = $StopWatch.Elapsed; 
Write-Host ""; 
Write-Host "Single thread elapsed time: $elapsed"; 
Write-Host "Synchronous return value count " $resultsSynchronous.Count; 
+0

'-AsJob'スイッチで同期方式を試しましたか? 'Get-Job'を使ってタスクを監視することができます。コマンドはインポートされるので、遅くなるだけです。オブジェクトと変数をランスペースにインポートする方法はありますが、あなたが認識しているように、ランスペースの操作は非常に迅速になります。 あなたがランスペースを使用することを意図している場合、@boeproxには[自分のブログのための方法]があります(https://learn-powershell.net/2013/04/19/sharing-variables-and-live-objects-between- powershell-runspaces /)を使用していますが、これはインポートされたジョブではありませんが、ジョブを複数回スレッドするためのガイドとして使用しています。 – brendan62269

+0

返信@ brendan62269、あなたが提供したリンクを勉強した後、私が正しく理解していれば、私は彼の例がハッシュテーブル内の戻り値を共有するものだと考えています。たぶん私はそれを見逃しているかもしれませんが、インポートされたセッションを.setVariableコマンドでどのように共有できますか? sessionState.Modules.Add()コマンドを使用していますか?所有権はモジュールと見なされますが、私は信じていませんが? – Jay

+0

それは正しい方法ではないかもしれません。セッションを最初に解決してから引数として使用しましたか?私は一例を挙げるためにコメントに十分なスペースがありません。私はそれを答えとして書くつもりです。 – brendan62269

答えて

0

同期されたリストは実際には私が考えていたものではなく、ライブセッションを引数として渡すだけで動作するはずです。あなたのforeachを行い

$importSession = new-pssession -ConfigurationName Microsoft.Exchange -ConnectionUri $connectionUri 

をしてからインポートするスクリプトブロックとセッションのadditionak引数にのparamsを追加します:ループの前にセッションを解決

foreach ($server in $servers) 
{ 
    $scriptBlock = { 
     param($importSession, $server) 
     import-pssession $importSession 
     Get-ExchangeServer -Identity $server 
     Get-MailboxDatabase -Server $server 
     Get-MailboxDatabase -Server $server -status 
    } 

    $asynchronousThreadCount++; 
    $runspaceObject = [PSCustomObject] @{ 
     Runspace = [PowerShell]::Create() 
     Invoker = $null 
    } 
    $runspaceObject.Runspace.RunSpacePool = $runspacePool; 
    $runspaceObject.Runspace.AddScript($scriptBlock) | Out-Null; 
    $runspaceObject.Runspace.AddArgument($importSession) | Out-Null; 
    $runspaceObject.Runspace.AddArgument($server) | Out-Null; 
    $runspaceObject.Invoker = $runspaceObject.Runspace.BeginInvoke(); 
    $threads += $runspaceObject; 
    $elapsed = $StopWatch.Elapsed; 

    Write-Host "Asynchronous created thread $asynchronousThreadCount " $elapsed; 
    $index++; 
} 

私はよそれを確認することはできません私は新しいスレッドをhttp://[something]/powershellにする必要はなく、毎回スレッドごとの読み込み時間を大幅に短縮する可能性があります。

関連する問題