如何在运行空间池中多次使用相同的 Exchange 会话状态信息?
How can I use the same Exchange session state information multiple times in a runspace pool?
我正在尝试创建一个完全为了速度优势的多线程脚本,我编写的同步版本可以运行但速度很慢。我遇到了瓶颈,因为每个线程都在导入 Exchange 会话信息,它比同步代码慢或慢,尤其是当服务器数量增加时。
我确定有更好的方法,我相信正确的方法是加载一次 pssession 并将其附加到运行空间池,但在我的搜索中我找不到一个工作示例如何使用 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;
同步列表也不是我真正想要的,只是将实时会话作为参数传递进来应该可行。解决循环前的会话:
$importSession = new-pssession -ConfigurationName Microsoft.Exchange -ConnectionUri $connectionUri
执行 foreach,然后将参数添加到脚本块和要导入的会话的附加参数:
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 执行新的 pssession 可能会显着减少每个线程的加载时间。
我正在尝试创建一个完全为了速度优势的多线程脚本,我编写的同步版本可以运行但速度很慢。我遇到了瓶颈,因为每个线程都在导入 Exchange 会话信息,它比同步代码慢或慢,尤其是当服务器数量增加时。
我确定有更好的方法,我相信正确的方法是加载一次 pssession 并将其附加到运行空间池,但在我的搜索中我找不到一个工作示例如何使用 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;
同步列表也不是我真正想要的,只是将实时会话作为参数传递进来应该可行。解决循环前的会话:
$importSession = new-pssession -ConfigurationName Microsoft.Exchange -ConnectionUri $connectionUri
执行 foreach,然后将参数添加到脚本块和要导入的会话的附加参数:
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 执行新的 pssession 可能会显着减少每个线程的加载时间。