proxb / PoshRSJob

Provides an alternative to PSjobs with greater performance and less overhead to run commands in the background, freeing up the console and allowing throttling on the jobs.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Start-RSJob: Throttle parameter have no effect inside a ForEach-Object block

jnury opened this issue · comments

Hi,

The following code has the expected behavior (2 simultaneous executions):

Measure-Command { 
    1..10 | Start-RSJob -ScriptBlock { Start-Sleep -Seconds 3 } -Throttle 2 | Wait-RSJob
}

[...]
Seconds           : 15

But the following one doesn't (all job run simultaneously):

measure-command { 
    1..10 | ForEach-Object { Start-RSJob -ScriptBlock { Start-Sleep -Seconds 3 } -Throttle 2 } | Wait-RSJob
}

[...]
Seconds           : 3

It's because Start-RSJob is called 1 time in the first code but 10 times in the second.

Do you think it's possible to workaround this behavior ? Maybe with a variable shared between different calls (like WebSession for Invoke-WebRequest) ?

ForEach-Object is really usefull when you want to pass multiple arguments to your scriptblock (or there is another way to do that ?).

hi,

have you tried -argumentlist or -variabletoimport param of start-rsjob ?

Please provide an real example where you want to pass the args.

Thank-you for your answer.

I did not tried VariableToImport so far. This is an example code (totally useless :-D):

$scriptblock = {
    param (
        $SleepSecond,
        $Status
    )
    Write-Warning "Service was $Status"
    Start-Sleep -Seconds $SleepSecond
}

Measure-Command {
    Get-Service | Select-Object -First 10 | ForEach-Object {
        $status = $_.Status.ToString()
        if ($status -eq 'Running') {
            $argumentList = @(2, 'Started')
        }
        else {
            $argumentList = @(4, 'Not started')
        }

        Start-RSJob -ScriptBlock $scriptblock -ArgumentList $argumentList -Name $_.Name -Throttle 2
    } | Wait-RSJob | Receive-RSJob
}

The result is 4 seconds (should between 10 and 20).

use -Batch - it is a key for runspace identification and throttking

Sorry I cannot get your point.
In your given example, whatever the number of service you set in 'select -first', the duration only depends on the max sleep seconds defined in $arguementList. In your case the max is 4, so the result is around 4 seconds ia good for me. start-rsjob is non blocking, the sleep in the start-rsjob scriptblock wont block ForEach.

@MVKozlov : thank you ! It works:

measure-command { 
    1..10 | ForEach-Object { Start-RSJob -ScriptBlock { Start-Sleep -Seconds 3 } -Throttle 2 -Batch 'Test' } | Wait-RSJob
}

[...]
Seconds           : 15

@copdips : the total duration should depends on the average duration of a job AND the Throttle parameter. In my example, it only depends on the max duration of a job.

I think to use really the -Throttle 2 in your example, you may remove the foreach block, and move the part between foreach and start-rsjob to the script block, and you send the service object directly to start-rsjob, than start-rsjob will run in 2 threads at the same time that will take 10 to 20 seconds.

please check.the param $InputObject of start-rsjob, only this param is ValueFromPipeline, only using it will make sense of -Throttle. in your example, start-rsjob doesn't use it. be aware that start-rsjob launches only non blocking async runspaces as long as the the maxrunspaces number is not reached in the same runspacepool.

https://github.com/proxb/PoshRSJob/blob/master/PoshRSJob/Public/Start-RSJob.ps1#L170

by using -batch, all the runspaces will get the same name even they are launched by foreach, so the -throttle defined in the first and the unique runspacepool will be reused each time. without -batch and in a foreach block, every start-rsjob will create a new runspacepool, 10 services so 10 independant runspacepools with only 1 runspace inside, each does its job (sleep) in //.

https://github.com/proxb/PoshRSJob/blob/master/PoshRSJob/Public/Start-RSJob.ps1#L505

https://github.com/proxb/PoshRSJob/blob/master/PoshRSJob/Public/Start-RSJob.ps1#L515

replace -batch "test" by batch "test_$($_.name)" will bring you back to 4 seconds as the runspacepool names are different from each other again.

Thank you for your explanations @copdips

I want to have the same runspacePool for all my jobs as this is the only way to have Throttle working. So everything is OK now with -Batch parameter