PowerShell 中 RunspacePool 执行异步多线程任务
在 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秒多一点点
============================================================================
写得有点乱,就当是笔记了
参考资料
Multithreading with PowerShell using RunspacePool
PowerShell 中 RunspacePool 执行异步多线程任务的更多相关文章
- 更优雅的方式: JavaScript 中顺序执行异步函数
火于异步 1995年,当时最流行的浏览器--网景中开始运行 JavaScript (最初称为 LiveScript). 1996年,微软发布了 JScript 兼容 JavaScript.随着网景.微 ...
- 解决Powershell中不能运行脚本问题
问题: powershell中不能执行脚本,提示‘because running scripts is disabled on this system’ 原因: powershell中默认的execu ...
- 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 ...
- 在UI程序设计中使用BackgroundWorker进行多线程异步处
WinForm的应用程序中如果执行了一个的非常冗长的处理操作,(比如文件检索,大运算量计算),在执行时就会锁定用户界面,虽然主活动窗口还在运行,但用户无法与程序交互,无法移动窗体或改变窗体大小,导致程 ...
- 在本地主机上powershell中连接远程主机执行vbs脚本,得到执行结果(2008版及以上)
在桌面版的主机上远程管理服务器版主机,在本地powershell中连接远程主机执行vbs脚本,得到执行结果. 执行步骤: 1.将本地主机上的Hyper.vbs复制到远程连接主机上.例如,本地vbs脚本 ...
- PowerShell因为在此系统中禁止执行脚本解决方法
PowerShell因为在此系统中禁止执行脚本解决方法 在Powershell直接脚本时会出现: 无法加载文件 ******.ps1,因为在此系统中禁止执行脚本.有关详细信息,请参阅 " ...
- Laravel框架中实现supervisor执行异步进程
问题描述:在使用Laravel框架实现动态网页时,若有些操作计算量较大,为了不影响用户体验,往往需要使用异步方式去处理.这里使用supervisor和laravel自带的queues实现. Super ...
- angularjs中如何在异步请求执行完以后再执行其他函数?
angularjs中如何在异步请求执行完以后再执行其他函数? 之前脑袋回路就是从上到下的执行js,直到有一次我的页面上已经显示了空才走到angularjs里的$http的成功回调函数里,然后才开始正视 ...
- Combine 框架,从0到1 —— 4.在 Combine 中执行异步代码
本文首发于 Ficow Shen's Blog,原文地址: Combine 框架,从0到1 -- 4.在 Combine 中执行异步代码. 内容概览 前言 用 Future 取代回调闭包 用输出类型( ...
随机推荐
- Chrome插件触发web页面的事件
Chrome插件中不能直接调用Web页面的元素js,原因是chrome插件的机制http://stackoverflow.com/questions/17819344/triggering-a-cli ...
- DDD - 概述 - 聚合 - 限界上下文 (四)
最重要的一句话 DDD的所有有相关理论中,只有一句是至关重要的,但是也是最容易被忽略和最难做到的,抛弃传统的设计方式(思路)的思想,这句话起了决定性的作用,但是99%的人都忽略了或者在开始无法正视或理 ...
- Sublime插件:Terminal
这几天在window环境下用gulp构建前端工程,切来切去浪费了不少时间(右键sublime菜单打开文件所在目录,然后去项目根目录,右键打开cmder).这点webstorm自带的Terminal真的 ...
- 结对开发项目--石家庄地铁web版
一.功能要求 1.数据库设计:将石家庄地铁线路图的各个线路,各个站点,换乘信息等用数据库的形式保存起来,应该保存的信息有 {线路号,线路的各个站名,车站的换乘信息}. 2.站点查询:用户可以输入任一一 ...
- 理解WindowManagerService
--摘自<Android进阶解密> *WMS的职责* 1)窗口管理 WMS负责窗口的启动.添加和删除,另外窗口的大小和层级也是由WMS进行管理的 2)窗口动画 WMS的动画子系统Windo ...
- 20162329张旭升 2018-2019-2《网络对抗技术》第1周 Kali的安装
目录 Kali的安装 设置与主机的文件交互 Kali的安装 1.创建虚拟机 2.选择安装语言 3.设置网络 4.设置分区 5.安装完成 设置与主机的文件交互 首先在vmware workstation ...
- BZOJ5335 : [TJOI2018]智力竞赛
二分答案,转化成求最少的路径,覆盖住所有权值$\leq mid$的点. 建立二分图,若$i$的后继为$j$,则连边$i\rightarrow j$,求出最大匹配,则点数减去最大匹配数即为最少需要的路径 ...
- 安装xlwt和xlrd
因为想用python实现读写excel.百度了下,要安装xlwt和xlrd,网上各种方法,很多都不便利.最后利用pip安装很方便. 第一步:浏览器检索“xlwt安装”,点击第一个网页(百度) 即出现如 ...
- CTF最简单的Web题
http://www.shiyanbar.com/ctf/1810 天网管理系统天网你敢来挑战嘛格式:ctf{ }解题链接: http://ctf5.shiyanbar.com/10/web1 查看源 ...
- jdk12+tomcat9 配置
jdk12 没有了jre的配置 直接配置path就可以了 tomcat常规配置,只是启动的时候麻烦一点 需要重新写入jdk jre jvm 到server.bat文件 参考文章: https: ...