看起来您在使用 powershell 之前至少已经了解一种其他语言,并且基本上是从在这一种语言中复制您可能在另一种语言中所做的事情开始的。这是学习新语言的好方法,但当然,一开始您可能会得到有点奇怪或性能不佳的方法。
首先我想分解一下你的代码实际上在做什么,作为一个粗略的概述:
- 一次读取文件的每一行并将其存储在
$Dict
多变的。
- 循环次数与行数相同。
- In each iteration of the loop:
- 获取与循环迭代匹配的单行(本质上是通过另一次迭代,而不是索引,稍后会详细介绍)。
- 获取该行的第一个字符,然后获取第二个字符,然后将它们组合起来。
- 如果它等于预先确定的字符串,则将此行附加到文本文件中。
步骤 3-1 才是真正减慢速度的原因
要了解原因,您需要了解一些有关 PowerShell 中的管道的知识。接受并在管道上工作的 Cmdlet 接受一个或多个对象,但它们一次处理一个对象。他们甚至无权访问管道的其余部分。
对于Select-Object
cmdlet。因此,当您获取一个包含 18,500 个对象的数组并将其通过管道传输到Select-Object -Index 18000
,您需要发送 17,999 件物品进行检查/处理,然后它才能给您您想要的物品。您可以看到索引越大,所花费的时间就会变得越来越长。
由于您已经有一个数组,因此您可以通过带方括号的索引直接访问任何数组成员[]
像这样:
$Dict[18000]
对于给定的数组,无论索引是什么,都需要相同的时间。
现在只需一次调用Select-Object -Index
即使索引非常大,您也可能不会注意到它需要多长时间;问题是你已经循环遍历了整个数组,所以这会大大加剧。
You're essentially having to do the sum of 1..18000
which is about or approximately 162,000,000 iterations! (thanks to user2460798 https://stackoverflow.com/users/2460798/user2460798 for correcting my math)
Proof
我测试了这个。首先,我创建了一个包含 19,000 个对象的数组:
$a = 1..19000 | %{"zzzz~$_"}
然后我测量了两种访问它的方法。首先,与select -index
:
measure-command { 1..19000 | % { $a | select -Index ($_-1 ) } | out-null }
Result:
TotalMinutes : 20.4383861316667
TotalMilliseconds : 1226303.1679
然后使用索引运算符 ([]
):
measure-command { 1..19000 | % { $a[$_-1] } | out-null }
Result:
TotalMinutes : 0.00788774666666667
TotalMilliseconds : 473.2648
结果非常惊人,需要长了近 2,600 倍 to use Select-Object
.
一个计数循环
以上是导致您的速度大幅下降的唯一原因,但我想指出其他一些事情。
通常在大多数语言中,您会使用for
循环计数。在 PowerShell 中,这看起来像这样:
for ($i = 0; $i -lt $total ; $i++) {
# $i has the value of the iteration
}
简而言之,里面有3个说法for
环形。第一个是在循环开始之前运行的表达式。$i = 0
将迭代器初始化为0
,这是第一个语句的典型用法。
接下来是条件句;这将在每次迭代中进行测试,如果返回 true,循环将继续。这里$i -lt $total
比较检查以查看$i
小于 的值$total
,其他地方定义的其他变量,大概是最大值。
最后一条语句在循环的每次迭代中执行。$i++
是相同的$i = $i + 1
所以在这种情况下我们要增加$i
在每次迭代中。
它比使用 a 更简洁一些do
/until
循环,并且更容易理解,因为 a 的含义for
循环是众所周知的。
其他注意事项
如果您有兴趣了解更多反馈working你写的代码,看看代码审查 https://codereview.stackexchange.com/。发帖前请仔细阅读那里的规则。