How does threading in powershell work?

Viewed 53506

I want to parallelize some file-parsing actions with network activity in powershell. Quick google for it, start-thread looked like a solution, but:

The term 'start-thread' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.

The same thing happened when I tried start-job.

I also tried fiddling around with System.Threading.Thread

[System.Reflection.Assembly]::LoadWithPartialName("System.Threading")
#This next errors, something about the arguments I can't figure out from the documentation of .NET
$tstart = new-object System.Threading.ThreadStart({DoSomething}) 
$thread = new-object System.Threading.Thread($tstart) 
$thread.Start()

So, I think the best would be to know what I do wrong when I use start-thread, because it seems to work for other people. I use v2.0 and I don't need downward compatibility.

4 Answers

The thing that comes closest to threads and is way more performant than jobs is PowerShell runspaces.

Here is a very basic example:

# the number of threads
$count = 10

# the pool will manage the parallel execution
$pool = [RunspaceFactory]::CreateRunspacePool(1, $count)
$pool.Open()

try {        
    # create and run the jobs to be run in parallel
    $jobs = New-Object object[] $count
    for ($i = 0; $i -lt $count; $i++) {
        $ps = [PowerShell]::Create()
        $ps.RunspacePool = $pool

        # add the script block to run
        [void]$ps.AddScript({
            param($Index)
            Write-Output "Index: $index"
        })

        # optional: add parameters
        [void]$ps.AddParameter("Index", $i)

        # start async execution
        $jobs[$i] = [PSCustomObject]@{
            PowerShell = $ps
            AsyncResult = $ps.BeginInvoke()
        }
    }
    foreach ($job in $jobs) {
        try {
            # wait for completion
            [void]$job.AsyncResult.AsyncWaitHandle.WaitOne()

            # get results
            $job.PowerShell.EndInvoke($job.AsyncResult)
        }
        finally {
            $job.PowerShell.Dispose()
        }
    }
}
finally {
    $pool.Dispose()
}

It also allows you to do more advanced things like

  • Throttle the number of parallel runspaces on the pool
  • Import functions and variables from the current session

etc.

The answer, now, is quite simple with the ThreadJob module according to Microsoft Docs.

Install-Module -Name ThreadJob -Confirm:$true

$Job1 = Start-ThreadJob `
                -FilePath $YourThreadJob `
                -ArgumentList @("A", "B")
$Job1 | Get-Job
$Job1 | Receive-Job
Related