MilestoneSystemsInc / PowerShellSamples

A collection of samples for managing your Milestone XProtect VMS using MilestonePSTools in PowerShell
https://www.milestonepstools.com
MIT License
37 stars 12 forks source link

Parallelism support #149

Closed Silex closed 1 month ago

Silex commented 2 months ago

Hello,

I wondered what would be the simplest way to get parallelism, ideally something like this:

Get-VmsCamera | Get-VmsCameraStream | Set-VmsCameraStream -Settings @{ FPS = 8 }

Currently I'm using a for loop on each camera, and I cannot help but feel this should be parallelizable...

joshooaj commented 2 months ago

Hi @Silex,

The most performant way without switching to C# code is probably to use runspaces via a module like Microsoft.PowerShell.ThreadJob which gives you the Start-ThreadJob command. It works similar to the Start-Job command but with less overhead since it runs in the same process in another runspace vs launching a new powershell process and running in a separate process and runspace.

Under most circumstances I haven't actually seen multithreading increase throughput enough to justify the added complexity. It seems like the management server serializes a lot of requests regardless of whether they're coming through the same WCF channel or unique WCF channels. But I haven't dug that deep into parallel performance for a couple of years so your mileage may vary.

I tried the following just now, and it just seems like the requests are deadlocked - they never complete.

$jobs = Get-VmsCamera | Get-VmsCameraStream -Enabled | % {
    Start-ThreadJob -ArgumentList $_ {
        param($stream)
        $stream | Set-VmsCameraStream -Settings @{ FPS = 0.3 }
    }
}
$jobs | Receive-Job -Wait -AutoremoveJob

image

joshooaj commented 2 months ago

This seems not to deadlock, but it's not faster on my small test setup with 48 total streams available on a handful of cameras. One of the drawbacks is the 1-second import time for the module since each runspace starts from scratch, even if it's running as a thread in-process.

Get-VmsCamera | % {
    Start-ThreadJob -ArgumentList $_ {
        param($cam)
        ipmo milestonepstools
        $cam | Get-VmsCameraStream | Set-VmsCameraStream -Settings @{ FPS = '0.21' }
    }
} | Receive-Job -Wait -AutoRemoveJob
Silex commented 2 months ago

Well, I thought you needed multiple processes (not threads) as MilestonePSTools is not threadsafe/rentrant (#45).

Anyway you're probably right that the server will likely sequentialize requests anyway so speed increase will be minimal.

On a side note a found a weird typo for "Set-AdaptiveStreaming" on the website:

image

It says the file is named "Group-CamerasByModel.ps1" :-)

joshooaj commented 2 months ago

Typo fixed, thanks! And yeah you don't necessarily want to use Connect-Vms or Connect-ManagementServer in multiple runspaces in the same process, but technically you can use runspaces and do some work in parallel. Once you import the module in another runspace, that runspace is already "connected" because commands will reuse the singleton [MilestonePSTools.Connection.MilestoneConnection]::Instance.

The Get-VmsCameraReport command is an example of a command heavily using runspaces, though I'm not necessarily proud of the implementation. There's still limited value in my experience though when most of the commands are hitting the management server rather than branching out to query the recording server RecorderStatusService2 API for example.