标题: [问题求助] PowerShell多线程runspace怎么输出到控制台? [打印本页]
作者: 2198114498 时间: 2025-1-13 15:38 标题: PowerShell多线程runspace怎么输出到控制台?
很奇怪,我又改了两版,暂时不能复现了,其中之一应该是之前的问题代码,但当时没保存,除了Job类忘了改过哪了。
1、这版添了几行输出就没再死锁?!- class Job {
- Init() {
- $this.ps.Streams.Information.add_DataAdded( {
- Param ( [Object]$sender, [System.Management.Automation.DataAddedEventArgs]$e )
- $i=0
- while(!($all = $sender.ReadAll())) {$i++;Write-Warning [Information] ReadAll阻塞:$i;Start-Sleep -Milliseconds 10}
- foreach($o in $all) { Write-Host $o }
- })
-
- }
-
- }
复制代码
2、这是之前的版本,当时出死锁问题,- class Job {
- Init() {
- $this.ps.Streams.Information.add_DataAdded( {
- Param ( [Object]$sender, [System.Management.Automation.DataAddedEventArgs]$e )
- foreach($o in $sender.ReadAll()) { Write-Host $o }
- })
- }
-
- }
复制代码
在官网查到
https://learn.microsoft.com/zh-c ... powershellsdk-1.1.0
我理解是遇到阻塞返回空,就添加了while代码
原问题:
想实现多线程,搜到推荐runspace,试了试AI给的代码,只能运行完才能看输出,
搜到一种方法,自己改了改,虽然能实时看到输出了,但是大概率会出现线程代码不返回,
怀疑是多线程死锁,但是没有能力调试和解决,请大神帮忙看看,先谢了!
1、注释71行代码,就不能实时输出了,但是不会死锁。。。
2、偶尔还出现过报错:
不能对 Null 值表达式调用方法。
所在位置 :56 字符: 5
+ $RunspacePool.Close()
所在位置 :37 字符: 16
+ while ($Jobs.IsCompleted() -contains $false) {
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: ( [],RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull- cls
- # 处理任务
- $Worker = {
- param($Filename)
- $i=0
- Write-Host "Processing $filename"
- $i=1
- #[Threading.Thread]::Sleep(100)
- Start-Sleep -Seconds 1 # Doing some work....
- $i=2
- Write-Host "Processed $filename"
- $i=3
- }
- # 最大并发
- $MaxRunspaces = 10
-
- try {
- # 线程池
- $RunspacePool = [runspacefactory]::CreateRunspacePool(1, $MaxRunspaces)
- $RunspacePool.Open()
-
- $Filenames = @("file1.txt", "file2.txt", "file3.txt", "file4.txt", "file5.txt", "file6.txt", "file7.txt", "file8.txt", "file9.txt", "file10.txt", "file11.txt")
-
- while($true) {
- # 开始时间
- $StartTime = Get-Date
- $Jobs = New-Object System.Collections.ArrayList
-
- foreach ($File in $Filenames) {
- Write-Host "Creating runspace for $File"
- $job=[Job]::new($RunspacePool)
- $null=$job.GetPowerShell().AddScript($Worker).AddArgument($File)
- $null=$Jobs.Add($job)
- $job.Run()
- }
-
- while ($Jobs.IsCompleted() -contains $false) {
- Write-Host (Get-date).Tostring() "Still running..."
- #[Threading.Thread]::Sleep(1000)
- Start-Sleep 1
- $Jobs.IsCompleted()
- }
- # 结束时间
- $endTime = Get-Date
- # 运行时间
- Write-Host "The script runs for Total time (s):$(($endTime - $StartTime).TotalSeconds)"
- # 任务对象信息
- $Jobs.GetPowerShell().Streams.Information
- $Jobs.GetPowerShell().haderrors
- $c=Read-Host '输入e退出'
- if($c -eq 'e') {break}
- }
- }
- finally {
- # 始终关闭进程池
- $RunspacePool.Close()
- }
-
-
- class Job {
- hidden [powershell]$ps = [powershell]::Create()
- hidden [IAsyncResult]$result
-
- Job([System.Management.Automation.Runspaces.RunspacePool]$runspacepool) {
- $this.ps.RunspacePool = $runspacepool
- $this.Init()
- }
-
- Init() {
- $this.ps.Streams.Information.add_DataAdded( {
- Param ( [Object]$sender, [System.Management.Automation.DataAddedEventArgs]$e )
- while(!($all = $sender.ReadAll())) {Start-Sleep -Milliseconds 10}
- foreach($o in $all) { Write-Host $o }
- })
- }
-
- [powershell] GetPowerShell() {
- return $this.ps
- }
-
- [IAsyncResult] GetResult() {
- return $this.result
- }
-
- [bool]IsCompleted() {
- return $this.result.IsCompleted
- }
-
- [IAsyncResult] Run() {
- return $this.result = $this.ps.BeginInvoke()
- }
- }
复制代码
作者: flashercs 时间: 2025-1-13 16:15
本帖最后由 flashercs 于 2025-1-13 16:17 编辑
powershell 有个简单的多线程方法是 workflow,但是workflow不支持完整的powershell features,且不支持pwsh 6+,例如:powershell 5.1
不支持Write-Host- workflow work1 {
- $Filenames = @("file1.txt", "file2.txt", "file3.txt", "file4.txt", "file5.txt", "file6.txt", "file7.txt", "file8.txt", "file9.txt", "file10.txt", "file11.txt")
- # workflow有很多限制
- # foreach -parallel允许同时最多开启5个线程
- foreach -parallel ($Filename in $Filenames) {
- $i=0
- "Processing $filename"
- $i=1
- #[Threading.Thread]::Sleep(100)
- Start-Sleep -Seconds 1 # Doing some work....
- $i=2
- "Processed $filename"
- $i=3
- }
-
- }
- [System.Diagnostics.Stopwatch]$watch = [System.Diagnostics.Stopwatch]::StartNew()
- work1
- $watch.Stop()
- $watch.Elapsed # 耗时2.21秒
复制代码
作者: 2198114498 时间: 2025-1-13 17:05
回复 2# flashercs
非常感谢!使用Win10自带应该是5.1,目前还在试验多线程就遇到不少问题,预想的功能还没添加。
我原想是控制台输入路径,开一个主线程读取文件,然后将字符串共享给多个处理线程,
然后主线程继续读取下一个文件,处理线程将结果输出到控制台。
不知workflow能实现吗
作者: Five66 时间: 2025-1-13 18:49
直接就写在一起啦 , 看得脑阔疼- #Runspace最大数
- $MaxRunspaces = 10
-
- #Runspace池
- $RunspacePool = [runspacefactory]::CreateRunspacePool(1, $MaxRunspaces)
- $RunspacePool.Open()
-
- #任务
- $Worker = {
- param($Filename)
- if(test-path $Filename){
- $all = gc $Filename
- foreach($o in $all) { [console]::writeline($o)}
- $rt=0
- }else{
- $rt=-1
- }
- $rt
- }
-
- $Filenames = @("file1.txt", "file2.txt", "file3.txt", "file4.txt", "file5.txt", "file6.txt", "file7.txt", "file8.txt", "file9.txt", "file10.txt", "file11.txt")
-
- $jobs = @()
-
- #添加并执行任务
- foreach ($File in $Filenames) {
- $ps = [Powershell]::Create()
- $job = $ps.AddScript($Worker).AddArgument($File)
- $job.RunspacePool = $RunspacePool
- $jobs += New-Object PSObject -Property @{
- Job = $job
- PowerShell = $ps
- Result = $job.BeginInvoke()
- }
- }
-
- #判断任务是否完成
- do{
- Start-Sleep -Milliseconds 500
- $c = ($jobs | Where {$_.Result.IsCompleted -ne $true}).Count
- Write-Host ("未完成任务数" + $c) -ForegroundColor Green
- }while($c -gt 0)
-
- #获取返回结果并释放资源
- $i=1;foreach($j in $jobs){
- $r = $j.Job.EndInvoke($j.Result)
- write-host "任务 $i 返回值 : $r" -ForegroundColor Yellow
- $j.PowerShell.Dispose()
- $i+=1
- }
-
- cmd /c pause
复制代码
没啥特别需求可以用多进程的start-job
欢迎光临 批处理之家 (http://bbs.bathome.net/) |
Powered by Discuz! 7.2 |