Informazioni sui processi threadAbout Thread Jobs

Breve descrizioneShort description

Fornisce informazioni sui processi basati su thread di PowerShell.Provides information about PowerShell thread-based jobs. Un processo thread è un tipo di processo in background che esegue un comando o un'espressione in un thread separato all'interno del processo della sessione corrente.A thread job is a type of background job that runs a command or expression in a separate thread within the current session process.

Descrizione lungaLong description

PowerShell esegue simultaneamente comandi e script tramite processi.PowerShell concurrently runs commands and scripts through jobs. Sono disponibili tre tipi di processi forniti da PowerShell per supportare la concorrenza.There are three jobs types provided by PowerShell to support concurrency.

  • RemoteJob -Comandi e script vengono eseguiti in una sessione remota.RemoteJob - Commands and scripts run in a remote session. Per informazioni, vedere about_Remote_Jobs.For information, see about_Remote_Jobs.
  • BackgroundJob -I comandi e gli script vengono eseguiti in un processo separato nel computer locale.BackgroundJob - Commands and scripts run in a separate process on the local machine. Per altre informazioni, vedere About Jobs (Informazioni sui processi).For more information, see about_Jobs.
  • PSTaskJob o ThreadJob : i comandi e gli script vengono eseguiti in un thread separato nello stesso processo nel computer locale.PSTaskJob or ThreadJob - Commands and scripts run in a separate thread within the same process on the local machine.

I processi basati su thread non sono altrettanto affidabili come i processi in background e remoti, perché vengono eseguiti nello stesso processo su thread diversi.Thread-based jobs are not as robust as remote and background jobs, because they run in the same process on different threads. Se un processo presenta un errore critico che arresta il processo, tutti gli altri processi nel processo vengono interrotti.If one job has a critical error that crashes the process, then all other jobs in the process are terminated.

Tuttavia, i processi basati su thread richiedono un sovraccarico minore.However, thread-based jobs require less overhead. Non usano il livello di comunicazione remota o la serializzazione.They don't use the remoting layer or serialization. Gli oggetti risultato vengono restituiti come riferimenti a oggetti attivi nella sessione corrente.The result objects are returned as references to live objects in the current session. Senza questo overhead, i processi basati su thread vengono eseguiti più velocemente e utilizzano un minor numero di risorse rispetto agli altri tipi di processo.Without this overhead, thread-based jobs run faster and use fewer resources than the other job types.

Importante

La sessione padre che ha creato il processo monitora anche lo stato del processo e raccoglie i dati della pipeline.The parent session that created the job also monitors the job status and collects pipeline data. Il processo figlio del processo viene terminato dal processo padre una volta che il processo ha raggiunto lo stato completato.The job child process is terminated by the parent process once the job reaches a finished state. Se la sessione padre viene terminata, tutti i processi figlio in esecuzione vengono terminati insieme ai relativi processi figlio.If the parent session is terminated, all running child jobs are terminated along with their child processes.

Esistono due modi per aggirare questa situazione:There are two ways work around this situation:

  1. Utilizzare Invoke-Command per creare processi eseguiti in sessioni disconnesse.Use Invoke-Command to create jobs that run in disconnected sessions. Per ulteriori informazioni, vedere about_Remote_Jobs.For more information, see about_Remote_Jobs.
  2. Utilizzare Start-Process per creare un nuovo processo anziché un processo.Use Start-Process to create a new process rather than a job. Per ulteriori informazioni, vedere Start-Process.For more information, see Start-Process.

Come avviare e gestire processi basati su threadHow to start and manage thread-based jobs

Esistono due modi per avviare i processi basati su thread:There are two ways to start thread-based jobs:

  • Start-ThreadJob-dal modulo ThreadJobStart-ThreadJob - from the ThreadJob module
  • ForEach-Object -Parallel -AsJob -la funzionalità parallela è stata aggiunta in PowerShell 7,0ForEach-Object -Parallel -AsJob - the parallel feature was added in PowerShell 7.0

Utilizzare gli stessi cmdlet Job descritti in about_Jobs per gestire i processi basati su thread.Use the same Job cmdlets described in about_Jobs to manage thread-based jobs.

Uso di Start-ThreadJobUsing Start-ThreadJob

Il modulo ThreadJob è stato prima fornito con PowerShell 6.The ThreadJob module first shipped with PowerShell 6. Può anche essere installato dalla PowerShell Gallery per Windows PowerShell 5,1.It can also be installed from the PowerShell Gallery for Windows PowerShell 5.1.

Per avviare un processo thread nel computer locale, usare il Start-ThreadJob cmdlet con un comando o uno script racchiuso tra parentesi graffe ( { } ).To start a thread job on the local computer, use the Start-ThreadJob cmdlet with a command or script enclosed in curly braces ({ }).

Nell'esempio seguente viene avviato un processo thread che esegue un Get-Process comando nel computer locale.The following example starts a thread job that runs a Get-Process command on the local computer.

Start-ThreadJob -ScriptBlock { Get-Process }

Il Start-ThreadJob comando restituisce un ThreadJob oggetto che rappresenta il processo in esecuzione.The Start-ThreadJob command returns a ThreadJob object that represents the running job. L'oggetto processo contiene informazioni utili sul processo, incluso lo stato di esecuzione corrente.The job object contains useful information about the job including its current running status. Raccoglie i risultati del processo durante la generazione dei risultati.It collects the results of the job as the results are being generated.

Uso di ForEach-Object -Parallel -AsJobUsing ForEach-Object -Parallel -AsJob

PowerShell 7,0 ha aggiunto un nuovo parametro impostato sul ForEach-Object cmdlet.PowerShell 7.0 added a new parameter set to the ForEach-Object cmdlet. I nuovi parametri consentono di eseguire blocchi di script nei thread paralleli come processi di PowerShell.The new parameters allow you to run script blocks in parallel threads as PowerShell jobs.

È possibile inviare dati tramite pipe a ForEach-Object -Parallel .You can pipe data to ForEach-Object -Parallel. I dati vengono passati al blocco di script che viene eseguito in parallelo.The data is passed to the script block that is run in parallel. Il -AsJob parametro crea oggetti Jobs per ciascuno dei thread paralleli.The -AsJob parameter creates jobs objects for each of the parallel threads.

Il comando seguente avvia un processo che contiene processi figlio per ogni valore di input inviato tramite pipe al comando.The following command starts a job that contains child jobs for each input value piped to the command. Ogni processo figlio esegue il Write-Output comando con un valore di input inviato tramite pipe come argomento.Each child job runs the Write-Output command with a piped input value as the argument.

1..5 | ForEach-Object -Parallel { Write-Output $_ } -AsJob

Il ForEach-Object -Parallel comando restituisce un PSTaskJob oggetto che contiene i processi figlio per ogni valore di input inviato tramite pipe.The ForEach-Object -Parallel command returns a PSTaskJob object that contains child jobs for each piped input value. L'oggetto processo contiene informazioni utili sui processi figlio in cui viene eseguito lo stato.The job object contains useful information about the child jobs running status. Raccoglie i risultati dei processi figlio durante la generazione dei risultati.It collects the results of the child jobs as the results are being generated.

Come attendere il completamento di un processo e recuperare i risultati del processoHow to wait for a job to complete and retrieve job results

È possibile usare i cmdlet del processo di PowerShell, ad esempio Wait-Job e, Receive-Job per attendere il completamento di un processo e restituire tutti i risultati generati dal processo.You can use PowerShell job cmdlets, such as Wait-Job and Receive-Job to wait for a job to complete and then return all results generated by the job.

Il comando seguente avvia un processo thread che esegue un Get-Process comando, quindi attende il completamento del comando e infine restituisce tutti i risultati generati dal comando.The following command starts a thread job that runs a Get-Process command, then waits for the command to complete, and finally returns all data results generated by the command.

Start-ThreadJob -ScriptBlock { Get-Process } | Wait-Job | Receive-Job

Il comando seguente avvia un processo che esegue un Write-Output comando per ogni input inviato tramite pipe, quindi attende il completamento di tutti i processi figlio e infine restituisce tutti i risultati dei dati generati dai processi figlio.The following command starts a job that runs a Write-Output command for each piped input, then waits for all child jobs to complete, and finally returns all data results generated by the child jobs.

1..5 | ForEach-Object -Parallel { Write-Output $_ } -AsJob | Wait-Job | Receive-Job

Il Receive-Job cmdlet restituisce i risultati dei processi figlio.The Receive-Job cmdlet returns the results of the child jobs.

1
3
2
4
5

Poiché ogni processo figlio viene eseguito in parallelo, l'ordine dei risultati generati non è garantito.Because each child job runs parallel, the order of the generated results is not guaranteed.

Prestazioni processo threadThread job performance

I processi thread sono più veloci e più semplici rispetto ad altri tipi di processi.Thread jobs are faster and lighter weight than other types of jobs. Ma hanno ancora un sovraccarico che può essere elevato rispetto al lavoro svolto dal processo.But they still have overhead that can be large when compared to work the job is doing.

PowerShell esegue comandi e script in una sessione.PowerShell runs commands and script in a session. È possibile eseguire un solo comando o uno script alla volta in una sessione.Only one command or script can run at a time in a session. Quando si eseguono più processi, ogni processo viene eseguito in una sessione separata.So when running multiple jobs, each job runs in a separate session. Ogni sessione contribuisce al sovraccarico.Each session contributes to the overhead.

I processi dei thread garantiscono prestazioni ottimali quando le operazioni eseguite sono maggiori del sovraccarico della sessione utilizzata per eseguire il processo.Thread jobs provide the best performance when the work they perform is greater than the overhead of the session used to run the job. Esistono due casi per che soddisfano questi criteri.There are two cases for that meet this criteria.

  • Lavoro con utilizzo intensivo di calcolo: l'esecuzione di uno script in più processi di thread può trarre vantaggio da più core del processore e da completare più velocemente.Work is compute intensive - Running a script on multiple thread jobs can take advantage of multiple processor cores and complete faster.

  • Il lavoro è costituito da uno script di attesa significativo, che dedica tempo in attesa di I/O o risultati della chiamata remota.Work consists of significant waiting - A script that spends time waiting for I/O or remote call results. L'esecuzione in parallelo viene in genere completata più rapidamente rispetto a se eseguita in sequenza.Running in parallel usually completes quicker than if run sequentially.

(Measure-Command {
    1..1000 | ForEach { Start-ThreadJob { Write-Output "Hello $using:_" } } | Receive-Job -Wait
}).TotalMilliseconds
36860.8226

(Measure-Command {
    1..1000 | ForEach-Object { "Hello: $_" }
}).TotalMilliseconds
7.1975

Nel primo esempio precedente viene illustrato un ciclo foreach che crea processi thread 1000 per eseguire una semplice scrittura di stringhe.The first example above shows a foreach loop that creates 1000 thread jobs to do a simple string write. A causa dell'overhead del processo, sono necessari più di 36 secondi per il completamento.Due to job overhead, it takes over 36 seconds to complete.

Nel secondo esempio viene eseguito il ForEach cmdlet per eseguire le stesse operazioni 1000.The second example runs the ForEach cmdlet to do the same 1000 operations. Questa volta, ForEach-Object viene eseguito in sequenza, in un singolo thread, senza alcun sovraccarico di processo.This time, ForEach-Object runs sequentially, on a single thread, without any job overhead. Viene completato in soli 7 millisecondi.It completes in a mere 7 milliseconds.

Nell'esempio seguente vengono raccolte fino a 5000 voci per 10 registri di sistema distinti.In the following example, up to 5000 entries are collected for 10 separate system logs. Poiché lo script prevede la lettura di un numero di log, è opportuno eseguire le operazioni in parallelo.Since the script involves reading a number of logs, it makes sense to do the operations in parallel.

$logNames.count
10

Measure-Command {
    $logs = $logNames | ForEach-Object {
        Get-WinEvent -LogName $_ -MaxEvents 5000 2>$null
    }
}

TotalMilliseconds : 252398.4321 (4 minutes 12 seconds)
$logs.Count
50000

Lo script viene completato a metà del momento in cui i processi vengono eseguiti in parallelo.The script completes in half the time when the jobs are run in parallel.

Measure-Command {
    $logs = $logNames | ForEach {
        Start-ThreadJob {
            Get-WinEvent -LogName $using:_ -MaxEvents 5000 2>$null
        } -ThrottleLimit 10
    } | Wait-Job | Receive-Job
}

TotalMilliseconds : 115994.3 (1 minute 56 seconds)
$logs.Count
50000

Processi e variabili di threadThread jobs and variables

Esistono diversi modi per passare i valori nei processi basati su thread.There are multiple ways to pass values into the thread-based jobs.

Start-ThreadJob può accettare variabili inviate tramite pipe al cmdlet, passate al blocco di script tramite la $using parola chiave o passate tramite il parametro ArgumentName .Start-ThreadJob can accept variables that are piped to the cmdlet, passed in to the script block via the $using keyword, or passed in via the ArgumentList parameter.

$msg = "Hello"

$msg | Start-ThreadJob { $input | Write-Output } | Wait-Job | Receive-Job

Start-ThreadJob { Write-Output $using:msg } | Wait-Job | Receive-Job

Start-ThreadJob { param ([string] $message) Write-Output $message } -ArgumentList @($msg) |
  Wait-Job | Receive-Job

ForEach-Object -Parallel accetta la pipe nelle variabili e le variabili passate direttamente al blocco di script tramite la $using parola chiave.ForEach-Object -Parallel accepts piped in variables, and variables passed directly to the script block via the $using keyword.

$msg = "Hello"

$msg | ForEach-Object -Parallel { Write-Output $_ } -AsJob | Wait-Job | Receive-Job

1..1 | ForEach-Object -Parallel { Write-Output $using:msg } -AsJob | Wait-Job | Receive-Job

Poiché i processi di thread vengono eseguiti nello stesso processo, qualsiasi tipo di riferimento variabile passato al processo deve essere trattato attentamente.Since thread jobs run in the same process, any variable reference type passed into the job has to be treated carefully. Se non è un oggetto thread-safe, non dovrebbe mai essere assegnato a e il metodo e le proprietà non devono mai essere richiamati su di esso.If it is not a thread safe object, then it should never be assigned to, and method and properties should never be invoked on it.

Nell'esempio seguente viene passato un oggetto .NET thread-safe ConcurrentDictionary a tutti i processi figlio per raccogliere oggetti processo denominati in modo univoco.The following example passes a thread-safe .NET ConcurrentDictionary object to all child jobs to collect uniquely named process objects. Poiché è un oggetto thread-safe, può essere usato in modo sicuro mentre i processi vengono eseguiti simultaneamente nel processo.Since it is a thread safe object, it can be safely used while the jobs run concurrently in the process.

$threadSafeDictionary = [System.Collections.Concurrent.ConcurrentDictionary[string,object]]::new()
$jobs = Get-Process | ForEach {
    Start-ThreadJob {
        $proc = $using:_
        $dict = $using:threadSafeDictionary
        $dict.TryAdd($proc.ProcessName, $proc)
    }
}
$jobs | Wait-Job | Receive-Job

$threadSafeDictionary.Count
96

$threadSafeDictionary["pwsh"]

NPM(K)  PM(M)   WS(M) CPU(s)    Id SI ProcessName
------  -----   ----- ------    -- -- -----------
  112  108.25  124.43  69.75 16272  1 pwsh

Vedere ancheSee also