在 PowerShell 中要执行任务脚本,现在通常使用 Runspace,效率很高;任务比较多时,用 Runspace pool 来执行异步操作,可以控制资源池数量,就像 C# 中的线程池一样

================================================

为了对比,我们分别采用同步和异步(多线程)方式,模拟执行10个任务,并且每个任务都接收一个参数,执行完成后返回执行结果

================================================

同步执行方法    输入参数 $toexecute 是一个任务脚本数组,方法内遍历任务脚本,直接通过脚本的 Invoke 方法执行(也可以创建一个 PowerShell 对象添加脚本,通过该 PowerShell 对象的 Invoke 方法执行),然后输出执行结果

# 执行同步(单线程)任务
function RunJob {
param($toexecute)
# 遍历执行所有脚本
[int]$arg = 0
foreach($s in $toexecute) {
$result = $s.Invoke($arg++) # 执行带参数的任务脚本
# 执行结果返回一个含有 Success 属性的对象
if ($result.Success) {
Write-Host (" -> 任务执行成功 " + $result.Data + ",当前线程 " + $result.ThreadId) -ForegroundColor Green
}
else {
Write-Host (" -> 任务执行失败 " + $result.Data + ",当前线程 " + $result.ThreadId) -ForegroundColor Red
}
}
}

异步执行方法    输入参数 $toexecute 是一个任务脚本数组,方法内遍历任务脚本,

通过 PowerShell 对象 $psl 添加执行脚本和参数,返回一个作业对象 $job
通过 Runspace pool 对象 $rsp 控制异步多线程,
通过 $job 的 BeginInvoke 方法提交异步操作,
通过轮询等待所有作业执行完成(IsCompleted),
通过 $job 的 EndInvoke 获得执行结果

# 执行异步(多线程)任务
function RunJobAsync {
param($toexecute)
$rsp = [RunspaceFactory]::CreateRunspacePool(1, 5) #设置资源池中Runspace数量最少和最多
$rsp.Open()
$jobs = @()
[int]$arg = 0
# 遍历执行所有脚本
foreach($s in $toexecute) {
$psl = [Powershell]::Create()
$job = $psl.AddScript($s).AddArgument($arg++) # 添加任务脚本和参数
$job.RunspacePool = $rsp
Write-Host $("添加任务... " + $job.InstanceId)
$jobs += New-Object PSObject -Property @{
Job = $job
PowerShell = $psl
Result = $job.BeginInvoke() # 异步执行任务脚本
}
} # 轮询等待任务完成
do
{
Start-Sleep -seconds 1
$cnt = ($jobs | Where {$_.Result.IsCompleted -ne $true}).Count
Write-Host ("运行中的任务数量: " + $cnt)
} while ($cnt -gt 0) foreach($r in $jobs) {
Write-Host ("任务结果: " + $r.Job.InstanceId)
$result = $r.Job.EndInvoke($r.Result) # 取得异步执行结果 # 注销 PowerShell 对象
$r.PowerShell.Dispose() # 输出完成的任务脚本
#Write-Output ($result) # 执行结果返回一个含有 Success 属性的对象
if ($result.Success) {
Write-Host (" -> 任务执行成功 " + $result.Data + ",当前线程 " + $result.ThreadId) -ForegroundColor Green
}
else {
Write-Host (" -> 任务执行失败 " + $result.Data + ",当前线程 " + $result.ThreadId) -ForegroundColor Red
}
}
}

初始化任务脚本,循环创建10个任务脚本,每个任务通过等待1秒钟模拟脚本执行,定义一个 PSObject 对象作为返回结果,其中属性 Success 代表是否成功(故意设置传入参数5时的任务失败),Data 代表执行结果,ThreadId 标识当前线程ID

这种方式就像 C# 中的方法委托一样(PowerShell 使用了大量.NET类库),在调用端用委托定义执行过程和结果,然后将委托以变量形式传递给执行端

$toexecute = @()  # 任务脚本列表
foreach($i in 1..10) {
$toexecute += {
param($state) #可接收参数
Start-Sleep -Seconds 1
New-Object PSObject -Property @{
Success = $state -ne 5 # 假设传入参数5时失败,其余成功
Data = "结果 $state" # 假设Data是执行结果,带上传入参数以区分
ThreadId = [AppDomain]::GetCurrentThreadId() # 当前线程ID
}
}
}

注:PowerShell 对象 AddScript 加载脚本执行,也可以传入一个脚本文件路径,因此每个任务脚本可以写到单独的 .ps1 文件中

============================================================================

下面调用同步方法 RunJob,并且测量执行时间

Clear-Host
$watch = Measure-Command {
RunJob -toexecute $toexecute
}
$elapsed = [Math]::Round($watch.TotalMilliseconds / 1000.0, 2)
Write-Output ("同步执行 "+ $toexecute.Count +" 个任务耗时" + $elapsed + "秒")

不出所料,在1个线程 20512 中执行10个任务,耗时10.06秒

============================================================================

下面调用异步方法 RunJobAsync,并且测量执行时间

Clear-Host
$watch = Measure-Command {
RunJobAsync -toexecute $toexecute
}
$elapsed = [Math]::Round($watch.TotalMilliseconds / 1000.0, 2)
Write-Output ("异步执行 "+ $toexecute.Count +" 个任务耗时" + $elapsed + "秒")

执行结果如下图,在5个线程中执行10个任务(差不多每个线程执行2个任务),耗时仅2.15秒

如果我们将代码中 [RunspaceFactory]::CreateRunspacePool(1, 5) 中最大资源数改为10,基本每个任务都能有1个线程执行,测试耗时就1秒多一点点

============================================================================

写得有点乱,就当是笔记了

参考资料

PowerShell runspace 的创建,使用和查错

Multithreading with PowerShell using RunspacePool

PowerShell 中 RunspacePool 执行异步多线程任务的更多相关文章

  1. 更优雅的方式: JavaScript 中顺序执行异步函数

    火于异步 1995年,当时最流行的浏览器--网景中开始运行 JavaScript (最初称为 LiveScript). 1996年,微软发布了 JScript 兼容 JavaScript.随着网景.微 ...

  2. 解决Powershell中不能运行脚本问题

    问题: powershell中不能执行脚本,提示‘because running scripts is disabled on this system’ 原因: powershell中默认的execu ...

  3. c#中@标志的作用 C#通过序列化实现深表复制 细说并发编程-TPL 大数据量下DataTable To List效率对比 【转载】C#工具类:实现文件操作File的工具类 异步多线程 Async .net 多线程 Thread ThreadPool Task .Net 反射学习

    c#中@标志的作用   参考微软官方文档-特殊字符@,地址 https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/toke ...

  4. 在UI程序设计中使用BackgroundWorker进行多线程异步处

    WinForm的应用程序中如果执行了一个的非常冗长的处理操作,(比如文件检索,大运算量计算),在执行时就会锁定用户界面,虽然主活动窗口还在运行,但用户无法与程序交互,无法移动窗体或改变窗体大小,导致程 ...

  5. 在本地主机上powershell中连接远程主机执行vbs脚本,得到执行结果(2008版及以上)

    在桌面版的主机上远程管理服务器版主机,在本地powershell中连接远程主机执行vbs脚本,得到执行结果. 执行步骤: 1.将本地主机上的Hyper.vbs复制到远程连接主机上.例如,本地vbs脚本 ...

  6. PowerShell因为在此系统中禁止执行脚本解决方法

    PowerShell因为在此系统中禁止执行脚本解决方法   在Powershell直接脚本时会出现: 无法加载文件 ******.ps1,因为在此系统中禁止执行脚本.有关详细信息,请参阅 " ...

  7. Laravel框架中实现supervisor执行异步进程

    问题描述:在使用Laravel框架实现动态网页时,若有些操作计算量较大,为了不影响用户体验,往往需要使用异步方式去处理.这里使用supervisor和laravel自带的queues实现. Super ...

  8. angularjs中如何在异步请求执行完以后再执行其他函数?

    angularjs中如何在异步请求执行完以后再执行其他函数? 之前脑袋回路就是从上到下的执行js,直到有一次我的页面上已经显示了空才走到angularjs里的$http的成功回调函数里,然后才开始正视 ...

  9. Combine 框架,从0到1 —— 4.在 Combine 中执行异步代码

    本文首发于 Ficow Shen's Blog,原文地址: Combine 框架,从0到1 -- 4.在 Combine 中执行异步代码. 内容概览 前言 用 Future 取代回调闭包 用输出类型( ...

随机推荐

  1. 2018-2019-2 网络对抗技术 20165323 Exp3 免杀原理与实践

    一.实践内容 1.1 正确使用msf编码器,msfvenom生成如jar之类的其他文件,veil-evasion,加壳工具,使用shellcode编程 1.2 通过组合应用各种技术实现恶意代码免杀 ( ...

  2. 简易promise的实现(二)

    code 上一章中我们遇到了两个问题 1.异步调用顺序的问题 2.then返回一个promise的问题 思考 如果控制异步回调的顺序? 因为异步操的时间作我们无法控制,但是我们只需要按顺序执行回调函数 ...

  3. python tensorflow model

    step01_formula # -*- coding: utf-8 -*- """ 단순 선형회귀방정식 : x(1) -> y - y = a*X + b (a ...

  4. 学习使人快乐6--XML

    一.XML概念 Extensible Markup Language,翻译过来为可扩展标记语言.Xml技术是w3c组织发布的,目前推荐遵循的是W3C组织于2000发布的XML1.0规范. 二.学习XM ...

  5. python+adb实现自动化获取手机信息

    首先我们先看一下使用adb查看Android手机信息的指令 #获取手机名称NAME = 'adb shell getprop ro.product.model'#获取手机版本VERSION = 'ad ...

  6. Python面向对象编程指南

    Python面向对象编程指南(高清版)PDF 百度网盘 链接:https://pan.baidu.com/s/1SbD4gum4yGcUruH9icTPCQ 提取码:fzk5 复制这段内容后打开百度网 ...

  7. ESP32 Eclipse开发环境构建与问题总结

    搞了一个多星期的eclipse环境构建,终于成功了,在此记录下期间遇到的问题. 以下为遇到的几点问题的解决方法: 1.使用的版本为V3.1版本,版本时间为2018年09月07日,可以直接在以下路径下载 ...

  8. Tomcat手动部署Web项目详细步骤

    阅读须知:文章基于Tomcat8,其它版本若有差异,请自行辨别.本文为博主原创文章,转载请附原文链接. 不借助任何IDE,这里介绍在Tomcat中手动部署web项目的三种方式: 1.部署解包的weba ...

  9. TCP(控制传输协议)详解

    1.传输层概述 在OSI参考模型中,网络层是面向通信的最高层但同时也是面向用户程序的最底层. 传输层的主要作用: 复用:在发送端,多个应用程序公用一个传输层: 分用:在接收端,传输层把从网络层接收到的 ...

  10. 自主学习python文本进度条及π的计算

    经过自己一段时间的学习,已经略有收获了!在整个过程的进行中,在我逐渐通过看书,看案例,做题积累了一些编程python的经验以后,我发现我渐渐爱上了python,爱上了编程! 接下来,当然是又一些有趣的 ...