performance - 有没有办法从大命令中更快地流出数据?
问题描述
假设我正在使用get-childitem c:\*.* -recurse
并且正在使用它。在管道处理它之前,我必须等待整个 get-childitem 命令完成。有一些例外,例如select -first 2
神奇地停止前一个命令。无论如何,有没有办法提高输出,所以它立即写入而不是吸收大量的内存?我的一个想法是......(我知道这行不通,但它让这个想法得以传达)
[System.IO.File]::ReadLines("$(dir c:\*.* -recurse)")
我知道这是 Windows 的事情,因为 Linux 会在数据出现后立即处理它。但我知道,两个不同的世界。
我最担心的是内存使用...
这是一个很好的例子
(1..10000000) | where {$_ -like "*543*"}
这需要我的机器大约 100 秒
在哪里
(1..10000000).where({$_ -like "*543*"})
只用了 25 秒。
解决方案
在管道处理它之前,我必须等待整个 get-childitem 命令完成。
否:PowerShell 管道的重点是在对象可用时一个一个地处理它们,从而充当内存节流阀,使内存使用量保持不变,而与输入集合的大小无关。
警告:不要
(...)
在通过管道发送其输出的命令周围使用,因为这确实会首先在内存中完整收集该命令的输出。Cmdlet作为 PowerShell 的本机命令,天生就支持这种一对一的流式传输。
但是,某些 cmdlet,例如
Sort-Object
andGroup-Object
必须首先收集内存中的所有输入[1],作为概念上的必要性(例如,在比较所有项目之前,您无法生成排序输出)。谢谢,培根片。ConvertTo-Json
类似地,仅发出单个输出对象的cmdlet,例如,从预先收集的全部输入构造该对象。
同样,来自外部程序的stdout 输出逐行传递,因为这些行变得可用。
您可以通过将表达式包含在 中来将其转换为流式命令
& { ... }
,但这仅在表达式尚未在内存中构建完整的对象集合时才有用;例如,
& { 1.. 10000000 } | ...
不会为您带来任何好处,但
& { for ($i=0; $i -lt 10000000; ++$i) { $i } } | ...
会。最终,如果源 cmdlet / 程序 / 表达式本身不以流式方式发出输出对象(一个接一个,因为它们正在生成),那么你就不走运了。
但是,确实缺少的是按需停止管道处理的能力-目前只能Select-Object -First
这样做-请参阅我的这个答案。GitHub 上
有一个长期存在的功能请求,要求提供一种机制来按需停止管道。
顺便说一句:使用 PSv4+.Where()
方法确实比使用Where-Object
cmdlet(其内置别名为where
)更快,但.Where()
总是要求它操作的集合事先已全部加载到内存中。
但是,该.Where()
方法确实有能力通过'First'
作为第二个参数传递来停止处理剩余的项目,该参数在第一次匹配后停止;'First'
是[System.Management.Automation.WhereOperatorSelectionMode]
;的一个实例 将 的性能与 的性能进行
(1..1e6).Where({$_ -eq 10})
比较
(1..1e6).Where({$_ -eq 10}, 'First')
[1] 例如,PowerShell 不像Unix实用程序那样使用临时文件来缓解内存压力;sort
我的猜测是,这样做在 PowerShell 中并不是一个真正的选择:PowerShell 处理活动对象(而不是静态字符串)的能力将带来重大的序列化/反序列化挑战,这是要使用的临时文件。
推荐阅读
- python - 是否可以更改 pyplot 上的刻度频率与数据集长度无关并缩放?
- arm - 无法通过 SSH 连接到运行 dropbear sshd 的 QEMU 虚拟机
- java - 如何使用二维按钮数组刷新面板?
- javascript - 如何在 D3 Js 中将 y 轴(yDomain)值设置为最大值
- r - 从 R 中的数据框创建相关矩阵
- reactjs - 在同一个文件中同时添加命名组件和默认组件是否合法?
- r - 使用 pacman 在 Ubuntu 中安装 R 包时出现依赖项错误
- python - sqlite python - 从txt文件将记录读入表
- python - 如何从两个列表中创建堆叠条形图:考虑一个是集群,另一个是标志
- c# - 如果特定值在行内,则更改行中的背景颜色