powershell 中的线程如何工作?

问题描述 投票:0回答:5

我想在 powershell 中将一些文件解析操作与网络活动并行化。快速谷歌一下, 启动线程看起来像是一个解决方案,但是:

术语“启动线程”不被识别为 cmdlet、函数、脚本文件或可操作程序的名称。检查名称的拼写,或者如果包含路径,请验证路径是否正确,然后重试。

当我尝试开始工作时也发生了同样的事情。

我也尝试摆弄 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()

所以,我认为最好是知道当我使用启动线程时我做错了什么,因为它似乎对其他人有用。我用的是v2.0,不需要向下兼容。

multithreading powershell
5个回答
33
投票

Powershell 没有名为 Start-Thread 的内置命令。

然而,V2.0确实有PowerShell作业,它可以在后台运行,并且可以被认为相当于线程。您可以使用以下命令来处理作业:

Name Category Synopsis ---- -------- -------- Start-Job Cmdlet Starts a Windows PowerShell background job. Get-Job Cmdlet Gets Windows PowerShell background jobs that are running in the current ... Receive-Job Cmdlet Gets the results of the Windows PowerShell background jobs in the curren... Stop-Job Cmdlet Stops a Windows PowerShell background job. Wait-Job Cmdlet Suppresses the command prompt until one or all of the Windows PowerShell... Remove-Job Cmdlet Deletes a Windows PowerShell background job.

这是一个有关如何使用它的示例。要启动作业,请使用 start-job 并传递一个脚本块,其中包含您想要异步运行的代码:

$job = start-job { get-childitem . -recurse }

此命令将启动一个作业,递归获取当前目录下的所有子目录,然后您将立即返回到命令行。

您可以检查

$job

 变量以查看作业是否已完成等。如果您想等待作业完成,请使用:

wait-job $job

最后,要接收作业结果,请使用:

receive-job $job
    

9
投票
你不能像这样直接使用线程,但是你不能因为尝试而受到责备,因为一旦整个 BCL 摆在你面前,期望它的大部分都能工作并不完全是愚蠢的:)

PowerShell 在管道中运行脚本块,而管道又需要运行空间来执行它们。我前段时间在博客中介绍了如何为 v2 ctp3 滚动自己的 MT 脚本,但技术(和 API)仍然是相同的。主要工具是

[runspacefactory]

[powershell]
 类型。看看这里:

http://www.nivot.org/2009/01/22/CTP3TheRunspaceFactoryAndPowerShellAccelerators.aspx

以上是最轻量级的 MT 脚本编写方法。 v2 中通过 start-job、get-job 的方式提供后台作业支持,但我想您已经发现了这一点,并且看到它们相当重量级。


3
投票
最接近线程并且比作业性能更高的东西是 PowerShell

runspaces

这是一个非常基本的例子:

# 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() }
它还允许您做更高级的事情,例如

    限制池上并行运行空间的数量
  • 从当前会话导入函数和变量
等等


2
投票
根据

Microsoft Docs,现在的答案非常简单,使用

ThreadJob 模块。

Install-Module -Name ThreadJob -Confirm:$true $Job1 = Start-ThreadJob ` -FilePath $YourThreadJob ` -ArgumentList @("A", "B") $Job1 | Get-Job $Job1 | Receive-Job
    

0
投票
这是 PowerShell 5 控制台应用程序中的可行解决方案。您可以根据自己的喜好更改代码。

using assembly System; using assembly System.Threading; class Dartagnan{ static [void] Main() { $method = ([Dartagnan]::new().gettype().getmethods() | ? { $_.name -eq "Thr" })[0]; $intptr = $method.MethodHandle.GetFunctionPointer(); $object = [Dartagnan]::new(); $ts = New-Object System.Threading.ThreadStart $object, $intptr $thread = [System.Threading.Thread]::new($ts); $thread.Start(); [System.Console]::WriteLine("Old Thread Id :"+[System.Threading.Thread]::CurrentThread.ManagedThreadId); [System.Console]::Read(); } static [void] Thr() { [System.Threading.Thread]::Sleep(5000); [System.Console]::WriteLine("New Thread Id :"+ [System.Threading.Thread]::CurrentThread.ManagedThreadId); return; } } [Dartagnan]::Main(); Read-Host;
如果您只想创建一个新线程而不使用这些元素,您也可以使用 PowerShell Element。

using assembly System; [System.Console]::WriteLine("Old Thread Id:" + [System.Threading.Thread]::CurrentThread.ManagedThreadId) $powershell = [System.Management.Automation.PowerShell]::Create(); $powershell.AddScript({ [System.Threading.Thread]::Sleep(4000); [System.Console]::WriteLine("New Thread Id:" + [System.Threading.Thread]::CurrentThread.ManagedThreadId); return "Dartagnan"; }) $bi = $powershell.BeginInvoke(); Read-Host; $result = $powershell.EndInvoke($bi); Write-Host $result; Read-Host;
    
© www.soinside.com 2019 - 2024. All rights reserved.