简体   繁体   English

Powershell 运行空间多线程问题

[英]Powershell runspace multithreading question

In the example below, even though I cap the concurrent threads at 50, the code will (within seconds) process and go down to the foreach ($thread in $threads).在下面的示例中,即使我将并发线程限制为 50,代码仍将(在几秒钟内)处理并将 go 向下传递到 foreach($threads in $threads)。

Is this expected behavior because the runspace pool is doing wizardry in the background and will store all 2000 thread objects in memory, but only allow 50 active at any time?这是预期的行为,因为运行空间池在后台执行魔法并将所有 2000 个线程对象存储在 memory 中,但在任何时候只允许 50 个活动?

The reason behind my question is that I'm trying to figure out why the processing is not nearly as fast as it should be.我的问题背后的原因是我试图弄清楚为什么处理速度不如预期的那么快。

$runspacePool = [runspacefactory]::CreateRunspacePool(

    1, #Min Runspaces

    50 #Max Runspaces

);

$remoteMailboxes = Get-RemoteMailbox -Resultsize 2000;

foreach ($remoteMailbox in $remoteMailboxes)
{
    $powerShell = [powershell]::Create($sessionState);
    $powerShell.RunspacePool = $runspacePool;
    
    [void]$powerShell.AddScript({   
        Param ($alias<#, $paths, $filters, $exclusionsArrNoAsterisks#>)     
        [pscustomobject]@{

            alias = $alias;

        } | Out-Null;
        
# a bunch of processing that takes 30 seconds happens here  
        
        return $returnedMailboxObj;

    }) # end of add script

    $powerShell.AddParameter('alias', $remoteMailbox.Alias) | Out-Null;
    $returnVal = $powerShell.BeginInvoke();
    $temp = "" | Select powerShell,returnVal,server;
    $temp.powerShell = $powerShell;
    $temp.returnVal = $returnVal;
    $temp.server = $server;
    $threadStartTime = [DateTime]::Now.ToLongTimeString();
    $tuple = [tuple]::create([string]$server, [DateTime]$threadStartTime); 
    $threadTimerTemp.Add($tuple) | Out-Null;
    $threads.Add($temp) | Out-Null;
}

foreach ($thread in $threads)
{
    $threadsTemp.Add($thread) | Out-Null;
}

$endInvokeArr = New-Object System.Collections.ArrayList;
$threadsCompleted = New-Object System.Collections.ArrayList;
$threadsNotCompleted = New-Object System.Collections.ArrayList;
$threadsNotCompleted.Add("PlaceHolder") | Out-Null;

while ($threadsTemp.Count -gt 0)
{
    $threadsNotCompleted.Clear();
    Write-Host "Updated thread count" $threadsTemp.Count;
    for ($i = 0; $i -lt $threadsTemp.Count; $i++)
    {
        $threadIsCompleted = $threadsTemp[$i].returnVal.IsCompleted;
        if ($threadIsCompleted -eq $false)
        {
            #$completed = $false;
            $threadsNotCompleted.Add($thread) | Out-Null;
            # Ignore
        }
        else
        {
            $threadHandle = $threadsTemp[$i].returnVal.AsyncWaitHandle.Handle;
            $threadsCompleted.Add($threadHandle) | Out-Null;
            $endInvoke = $threadsTemp[$i].PowerShell.EndInvoke($threadsTemp[$i].returnVal);
            $endInvokeArr.Add($endInvoke) | Out-Null;
            $threadsTemp.Remove($threadsTemp[$i]);
            $i++;
        }
    }
    
    Write-Host "endInvokeArrCount" $endInvokeArr.Count;
    Write-Host "Threads completed count: " $threadsCompleted.Count;
    Write-Host "Threads count" $threadsTemp.Count;      

    sleep -Milliseconds 100;
} # while end   

Is this expected behavior because the runspace pool is doing wizardry in the background and will store all 2000 thread objects in memory, but only allow 50 active at any time?这是预期的行为,因为运行空间池在后台执行魔法并将所有 2000 个线程对象存储在 memory 中,但在任何时候只允许 50 个活动?

Yes!是的! This is the expected behavior这是预期的行为

The method PowerShell.BeginInvoke() could as well have been called PowerShell.ScheduleWorkForWheneverARunspaceIsReadyInTheFuture() - that is, BeginInvoke doesn't actual do any work before returning to the caller - it simply:方法PowerShell.BeginInvoke()也可以称为PowerShell.ScheduleWorkForWheneverARunspaceIsReadyInTheFuture() - 也就是说, BeginInvoke在返回给调用者之前实际上并没有任何工作 - 它很简单:

  • Ensures that an available runspace or runspacepool exists ,确保存在可用的运行空间或运行空间池,
  • Sets up the "pipes and duct-tape" needed for collecting output from the code to be run设置从要运行的代码中收集output所需的“管道和胶带”
  • Adds a "work order" to a queue to "schedule" that some runspace picks up the request将“工作订单”添加到队列以“安排”某些运行空间接收请求
  • Returns a "receipt" (the IAsyncResult object you briefly store in $returnval ) for the "work order" scheduled返回计划的“工作订单”的“收据”(您短暂存储在$returnval中的IAsyncResult object )

These relatively simple steps can obviously be completed much faster than actually executing the associated code, so it's not actually that unusual to be able to begin (ie "schedule") many more executions than can be run concurrently - heck, the runspace pool might not even have started executing the first request by the time you've scheduled the remaining 1999.这些相对简单的步骤显然可以比实际执行相关代码更快地完成,因此能够开始(即“调度”)比并发运行更多的执行实际上并不少见 - 哎呀,运行空间池可能不会甚至在您安排剩余的 1999 年时已经开始执行第一个请求。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM