PowerShell提速和多线程

概述

我们平时写脚本时,经常会提醒自己要多使用管道,要多使用流模式,少占内存,少占CPU。但是这篇文章会反其道而行之,少用管道,通过内存和CPU的占用来提高效率,也就是我们通常算法上说的用空间来换取时间。机器配置高,有的用,而不用就是浪费。

比如下面的场景:

  • 写一个大文件可能需要3.6分钟,提高性能后,只需3秒钟
  • 读一个大文件可能需要77秒钟,提高性能后,只需2秒钟
  • 检查250台机器的是否在线,需要23.2分钟,提高性能后,只需26秒钟

PowerShell性能提高前后对比图

PowerShell性能提高前后对比图

这一切性能的提升都是有偿的,需要你额外的投资。

投资更多内存

在PowerShell中推崇的管道主要是为了限制内存的使用量,让管道中的元素像流水线中的零件或者半成品一样,从车间一个一个穿过。但是管道并不是最快的,且看下面的随机数的例子。

管道流模式可以节省内存

管道流模式可以节省内存

随机数的例子

1

2

3

4

5

6

7

8

9

10

#这个很快

PS> 1..100 |Get-Random

90

 

#这个稍有延迟,可以容忍

PS> 1..10000 |Get-Random

4868

 

#这个慢的受不了,所以直接Ctrl-C取消。

PS> 1..1000000 |Get-Random

是不是就意味着1000000这么大的一个数组Get-Random天生就这么慢,非也。换个方法:

1

2

3

#这样做,快的一塌糊涂啊

PS> Get-Random -InputObject (1..1000000)

317486

原因是前者使用了管道,产生一条数据,流过一条数据。而后者是直接一次性产生全部数据,然后交给Get-Random,所以快。

写文件的例子

1

2

3

$all = @('Some Test' * 20)*1000000

$file "$Env:TEMP\testfile.txt"

$all Out-File $file

上面的脚本执行大概需要215 秒钟(3.6分钟)
换个方式,使用inputObject,仅用了101秒钟(1.8分钟)

1

Out-File $file -InputObject $all

是不是优化就止于此了呢,不,下面的结果会亮瞎我的眼睛啊,只需要2.5秒钟

1

[Io.file]::WriteAllLines( $file$all,[text.encoding]::Unicode)

真真没想到直接调用.NET方法差别会这么大,但是我用的是PowerShell,你给我整.NET方法,用键盘敲起来未免坑爹啊,那就试试Set-Content吧,只需要3.1秒钟

1

Set-Content $file -Value $all -Encoding Unicode

与WriteAllLine相比,稍慢,也可以忍受。

通过这个写文件的例子对比不难发现,3.6分钟/3.1秒钟=70,,速度几乎提高了70倍啊。

总结一下,写文件时注意两点即可:

  1. 不要使用管道。
  2. 不要使用神马的Out-这样的命令(因为它会做格式化)

读文件的例子

对于我们刚才创建的文本文件,一般读取时,我们习惯使用Get-Content,需要77秒钟(1.3分钟)

1

Get-Content $file

而如果使用.NET方法,只需1.8秒钟

1

[io.file]::ReadAllLines($file)

Get-Content为什么会这么慢,因为它要一行一行来读,并把读取的数据存储成数组,所以慢。但是Get-Content有一个参数ReadCount,把值设为0,一次性全部读取,只需2.2秒钟

1

Get-Content $file -ReadCount 0

把文件读出来一般是需要处理的,如果这样肯定不是你预期的,因为只会输出一个X:

1

Get-Content $file -ReadCount 0 | foreach {"X" }

这样就对了,只需要2.7秒钟

1

2

$text Get-Content $file -ReadCount 0

foreach ($line in $text) {'X'}

千万不要多次一举,引入管道,得68秒钟啊:

1

2

$text Get-Content $file -ReadCount 0 | foreach {"X" }

$text ForEach-Object {'X'}

警告

  • cmdlet明显非常慢
  • .NET一些底层的方法相对较快

解药

  • 不要轻易引入管道。
  • 尽量使用传统的For或者foreach循环

如果你还不相信,请继续看例子。

多用循环,少用管道的例子

1

1..1000000  | ForEach-Object "looping for the $_ Time"}

上面使用管道,执行时间为6.9秒钟。如果换成简单的For循环,只需要0.5秒钟,速度提高了14倍。

1

2

3

4

For $x=1; $x -le 100000;$x++)

{

  "Looping for the $x. time"

}

再看一个抑制输出的例子,三个写法效果一样,速度相差几十倍。

1

2

3

4

5

6

7

8

#耗时0.1毫秒

'Hello' |out-null

 

#耗时 0.002毫秒,速度提高了56倍

$null'Hello'

 

#耗时0.0025毫秒,速度也很快

[void] 'Hello'

 

因为我只用到了这些,故只粘贴到这里。

原文链接:https://www.pstips.net/speeding-up-powershell-multithreading.html

有兴趣的同学可以移步去原文链接看下!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值