我正在尝试学习编程/脚本编写的效率,并且我知道在后台发生的事情我可能不知道。
$sb = new-object System.text.stringbuilder;
$sb.append("Hello World");
Write-Host $sb.clear().append("Hello World 2");
Run Code Online (Sandbox Code Playgroud)
这是有效的还是它在后台执行.toString() ?
和
for (iteration) {
$temp = "test";
$temp = $null # Which is better?
# or
clear-variable temp # Which is better?
$temp = "test2"
[GC]::Collect(); # Is this needed?
}
Run Code Online (Sandbox Code Playgroud)
Eric Lippert 在这里的回答StringBuilder 如何工作(要求使用 C#,但适用于 PowerShell,因为它是相同的 .Net 类)说它在内部使用部件的链接列表。
这意味着它确实必须ToString()在后台执行类似的操作,将该数据结构转换为可用于打印的字符串。
这是另一个 StringBuilder 讨论- 特别是 BlueRaja 的回答。
for (iteration) {
$temp = "test";
$temp = $null # Which is better?
# or
clear-variable temp # Which is better?
$temp = "test2"
[GC]::Collect(); # Is this needed?
}
Run Code Online (Sandbox Code Playgroud)
$temp = $null执行简单的分配,Clear-Variable temp必须执行 cmdlet 名称解析、启动 cmdlet、参数绑定,并完成Clear-Variable具有更多功能的代码,即使您没有使用它们。但是先完成一项任务,然后进行下一项任务$temp = "test"; $temp = "test2"可能就可以了,而无需清除该值。
[GC]::Collect()强制垃圾收集器运行 - 这使得工作发生,并且做工作比什么都不做需要更长的时间,所以不需要在小范围内使任何事情更快。它在 PowerShell 中永远不需要(?),因为它总是会在某个时刻自动发生 - 但如果您已将数百 MB 或一些 GB 加载到内存中并且不再需要它,调用[GC]::Collect()可能有助于更快地释放它,并且可能会产生一些更大的数据处理脚本运行得更快一些。或许。
想知道后台发生了什么是值得尊重的——你应该这样做,当有更快的方法时,你可能会在没有意识到的情况下做非常慢的事情。
但 @Tomalak 在评论中所说的是明智的 - PowerShell 并不是为了尽可能快而构建的,它的构建是为了管理任务方便且可读,它不是一个连接复用网络服务器,也不是一个位移 3D 游戏引擎,它存在的原因是“将大量工作包装在几个命令中”。
“方便”就是用计算机的力量来节省人力。它做得更多,所以你必须写得更少。也就是说,在某种程度上,它意味着为了获得更多便利而故意权衡,速度会变慢。所有脚本语言都是。
可读意味着您希望更喜欢专注于任务的代码,而不是支持专注于幕后机制和触发垃圾收集器或其他内容的代码。再次重申,可用性高于性能。
我们距离 CPU 还很远,试试:
measure-command { $x = 1 }
measure-command { $x = 1 }
Run Code Online (Sandbox Code Playgroud)
对我来说,TotalMilliseconds = 第一次运行 5 毫秒,下次运行 1 毫秒。只要再做一次,就可以减少 80% 的运行时间。下次运行,1.3ms - 无缘无故慢了 30%。
.Net JIT 编译,系统上发生的其他任务,这是变量分配的微优化,对任何事情都没有影响,更改会在噪音中丢失。
由于这种影响,担心 PowerShell 中的微性能有点浪费时间。
但我确实看到,除非你了解了这一点,否则你无法知道什么值得担心,什么不值得,所以托马拉克的解雇“不要提前担心错误的事情”有点像第 22 条军规- 你不知道什么是错误的!“写点东西”是个好建议。缓慢解决问题的工作代码比花时间担心未来的代码可能会很慢要好得多。
写!当它缓慢且烦人时,请调查以找到最慢的部分并重写它们。当您做得足够多时,您在编写新代码时将避免最慢的事情,因为您知道它们是您经常重写的模式。
现在尝试
Measure-Command { $x = @(); foreach ($i in 1..10000) { $x += $i }}
Measure-Command { $x = foreach ($i in 1..10000) { $i }}
Run Code Online (Sandbox Code Playgroud)
3.5 秒 vs 0.015 秒。
哇。
当然,1..10000在内存中生成一个巨大的数组,当然我们可以通过使用计数器而不是生成数组来使其更好:
Measure-Command { $x = for ($i=1; $i -le 10000; $i++) { $i }}
Run Code Online (Sandbox Code Playgroud)
等等,那是0.03秒。它不仅更丑陋、不太方便,而且速度也更慢。PowerShell 层的测试和计数比较1..10000低级别的测试和计数要差。
值得担心吗?不,因为 0.015 或 0.03 秒实际上是在说“足够快,去看看代码的其他部分,比如读取整个文件十次”。3秒值得担心吗?
PowerShell 优化倾向于:
找到最常见的缓慢陷阱($thing +=循环中的字符串或数组串联,以及在开始进行任何处理之前将大的东西完全加载到内存中)并更改它们。数量不多,而且通过练习很容易发现它们 - 跳到循环所在的位置。
重新思考您的算法,以便在任何语言中都可以减少工作量。困难得多,但会让你获得更大的胜利。作为一个快速的操作,任何大的循环和相互比较数组通常都可以更改为使用 Group-Object哈希表,这在 PowerShell 的排序和报告类型中经常出现。
将其中一些推送到 C#。
当您担心 StringBuilder 是否调用 .ToString() 以及以某种方式或另一种方式清除变量是否会损害性能时,您要么关注错误的代码,要么最慢的位在其他地方,或者整体设计有问题,或者您已经超出了应该转向另一种语言的程度,因为 Powershell 的级别太高,无法为您提供毫秒级的控制。
| 归档时间: |
|
| 查看次数: |
739 次 |
| 最近记录: |