[powershell 入门教程] 第8天 任务计划、后台作业与多线程(Runspace)

部署运行你感兴趣的模型镜像

第8天:任务计划、后台作业与多线程(Runspace)

—— 实现本地可运行的并发自动化

💡 核心目标:掌握从“单线程脚本”到“高性能并行任务”的跃迁

一、为什么需要并发?—— 单线程的瓶颈

# 单线程:依次 Ping 5 个地址(耗时 ~5 秒)
"google.com", "github.com", "microsoft.com", "stackoverflow.com", "localhost" | ForEach-Object {
    $start = Get-Date
    Test-Connection $_ -Count 1 -ErrorAction SilentlyContinue | Out-Null
    Write-Host "$_ 耗时: $((Get-Date) - $start).TotalSeconds 秒"
}

🕒 总耗时 ≈ 各任务之和 → 无法满足批量运维需求


二、方案1:后台作业(Job)—— 简单但低效

✅ 优点:语法简单,完全隔离

❌ 缺点:每个 Job 启动新进程,内存/CPU 开销大

🔧 实践:用 Start-Job 并行 Ping
$servers = "google.com", "github.com", "microsoft.com", "localhost"

# 启动作业
$jobs = foreach ($server in $servers) {
    Start-Job -ScriptBlock {
        param($s)
        $result = Test-Connection $s -Count 1 -ErrorAction SilentlyContinue
        [PSCustomObject]@{
            Host   = $s
            Online = [bool]$result
            Time   = if ($result) { $result.ResponseTime } else { $null }
        }
    } -ArgumentList $server
}

# 等待并收集结果
$results = $jobs | Wait-Job | Receive-Job

# 清理(重要!)
$jobs | Remove-Job

# 输出
$results | Sort-Object Time | Format-Table -AutoSize

📊 性能提示:打开任务管理器,你会看到多个 pwsh.exepowershell.exe 进程同时运行。


三、方案2:PowerShell 7+ 原生并行 —— ForEach-Object -Parallel

✅ 优点:语法简洁、同进程多线程、开销小

❌ 缺点:仅限 PowerShell 7+,变量需用 $using: 引入

🔧 实践:并行检查本地端口是否开放

💡 💡 💡 💡 注意:需要安装PowerShell7,安装后可能需要运行pwsh来切换PowerShell版本,

查看版本方法 $PSVersionTable💡 💡 💡 💡

# 检查本机常用端口
$ports = 80, 443, 3389, 1433, 22, 3306

$portCheckScript = {
    param($port)
    $tcp = New-Object System.Net.Sockets.TcpClient
    $connect = $tcp.BeginConnect("127.0.0.1", $port, $null, $null)
    $wait = $connect.AsyncWaitHandle.WaitOne(1000, $false)  # 1秒超时
    $open = $false
    if ($wait) {
        try { $tcp.EndConnect($connect); $open = $true } catch {}
    }
    $tcp.Close()
    [PSCustomObject]@{ Port = $port; Open = $open }
}

# 并行执行(最多3线程)
$ports | ForEach-Object -Parallel $portCheckScript -ThrottleLimit 3 |
         Where-Object Open |
         Format-Table -AutoSize

✅ 输出示例(若 RDP 开启):

Port Open
---- ----
3389 True

💡 注意:若在 PowerShell 5.1 中运行,会报错“不支持 -Parallel”。


四、方案3:RunspacePool —— 高性能通用方案(兼容 PS 5.1+)

✅ 优点:同进程多线程、低开销、完全控制、跨版本兼容

🔧 封装为可复用函数 Invoke-Parallel

function Invoke-Parallel {
    param(
        [Parameter(Mandatory)] [object[]]$InputObject,
        [Parameter(Mandatory)] [scriptblock]$ScriptBlock,
        [int]$ThrottleLimit = 5
    )

    $runspacePool = [runspacefactory]::CreateRunspacePool(1, $ThrottleLimit)
    $runspacePool.Open()

    $jobs = @()
    foreach ($item in $InputObject) {
        $ps = [powershell]::Create().AddScript($ScriptBlock).AddArgument($item)
        $ps.RunspacePool = $runspacePool
        $jobs += [PSCustomObject]@{
            PowerShell = $ps
            Handle     = $ps.BeginInvoke()
        }
    }

    # 收集结果
    $results = foreach ($job in $jobs) {
        $job.PowerShell.EndInvoke($job.Handle)
        $job.PowerShell.Dispose()
    }

    $runspacePool.Close()
    $runspacePool.Dispose()
    return $results
}
🔧 实践:并行获取多个进程的 CPU 使用率(模拟耗时操作)
# 获取前5个高内存进程
$processes = Get-Process | Sort-Object WorkingSet -Descending | Select-Object -First 5 -ExpandProperty Name

# 模拟“获取详细指标”的耗时操作
$metricScript = {
    param($procName)
    Start-Sleep -Milliseconds (Get-Random -Min 200 -Max 800)  # 模拟延迟
    $proc = Get-Process -Name $procName -ErrorAction SilentlyContinue
    if ($proc) {
        [PSCustomObject]@{
            Process = $procName
            CPU     = [math]::Round(($proc.CPU | Measure-Object -Sum).Sum, 2)
            MemoryMB = [math]::Round(($proc.WorkingSet64 | Measure-Object -Sum).Sum / 1MB, 2)
        }
    }
}

# 并行执行(4线程)
Invoke-Parallel -InputObject $processes -ScriptBlock $metricScript -ThrottleLimit 4 |
                Sort-Object CPU -Descending |
                Format-Table -AutoSize

📊 性能对比

  • 单线程:~2–4 秒
  • Runspace(4线程):~0.8 秒
  • Job(4进程):~1.5 秒 + 更高内存占用

五、任务计划:让脚本自动运行

🎯 场景:每天凌晨清理临时文件

# 创建清理脚本
$scriptPath = "C:\Scripts\CleanupTemp.ps1"
@'
Get-ChildItem $env:TEMP -Recurse -Force |
Where-Object LastWriteTime -lt (Get-Date).AddDays(-7) |
Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
'@ | Set-Content -Path $scriptPath

# 注册任务(以 SYSTEM 身份每天 2:00 AM 运行)
$action = New-ScheduledTaskAction -Execute "pwsh.exe" -Argument "-File `"$scriptPath`""
$trigger = New-ScheduledTaskTrigger -Daily -At "2:00AM"
$principal = New-ScheduledTaskPrincipal -UserId "NT AUTHORITY\SYSTEM" -LogonType ServiceAccount

Register-ScheduledTask -TaskName "CleanupTempFiles" -Action $action -Trigger $trigger -Principal $principal

✅ 验证:打开 任务计划程序 → 查看“任务计划程序库”


六、三种并发方式对比总结

方式进程模型内存开销兼容性适用场景
Start-Job多进程❌ 高(每个 Job ≈ 100MB+)✅ PS 3+长时间运行、需完全隔离的任务
ForEach-Object -Parallel单进程多线程✅ 低❌ 仅 PS 7+快速开发、轻量级并行管道
RunspacePool单进程多线程✅ 低✅ PS 3+(需 .NET)高性能批量任务、企业脚本

📌 推荐策略

  • 日常脚本(PS 7+)→ 优先用 -Parallel
  • 企业级/兼容性要求高 → 用 Invoke-Parallel(Runspace 封装)
  • 需要独立环境(如不同用户上下文)→ 用 Start-Job

七、今日重点总结

  • ✅ 并发 ≠ 多进程:Runspace 是更高效的多线程方案
  • ✅ 所有异步操作后必须清理资源Remove-Job / Dispose()
  • ✅ 任务计划用 Register-ScheduledTask,而非已废弃的 ScheduledJob
  • ✅ 本地即可练习并发:用 Start-SleepTest-ConnectionGet-Process 模拟耗时操作

🏁 课后作业(全部本地可运行)

  1. 使用 Start-Job:启动3个后台作业,分别休眠3、5、7秒,记录总耗时 vs 单线程。
  2. 使用 ForEach-Object -Parallel(PS 7+):并行计算 1 到 10 的平方,并按输入顺序输出。
  3. 使用 Invoke-Parallel 函数:并行检查本机 80, 443, 3389, 1433, 22, 21 端口是否开放,输出开放端口列表。

💡 提示:端口检查可复用上文 $portCheckScript

您可能感兴趣的与本文相关的镜像

ACE-Step

ACE-Step

音乐合成
ACE-Step

ACE-Step是由中国团队阶跃星辰(StepFun)与ACE Studio联手打造的开源音乐生成模型。 它拥有3.5B参数量,支持快速高质量生成、强可控性和易于拓展的特点。 最厉害的是,它可以生成多种语言的歌曲,包括但不限于中文、英文、日文等19种语言

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值