我正在尝试下载10MB的文件并将其存储为数组以进行进一步处理。
使用直接调用(New-Object System.Net.WebClient).DownloadData("<url>")
时,一切似乎都很好。但是,如果我将其包装在函数中,然后将调用结果返回到WebClient::DownloadData
,则内存占用量将增加到500mb左右。
我使用的功能:
function My-Download {
param (
[Parameter(Mandatory = $True, Position = 1)] [String] $UrlCode
)
(New-Object System.Net.WebClient).DownloadData($UrlCode)
}
$x = My-Download("https://file-examples.com/wp-content/uploads/2017/04/file_example_MP4_1280_10MG.mp4")
我将其包装在函数中的原因是,在返回数据之前我也对数据进行了额外的处理,但即使是这个小例子也可以说明问题。
呼叫$x = (New-Object System.Net.WebClient).DownloadData("https://file-examples.com/wp-content/uploads/2017/04/file_example_MP4_1280_10MG.mp4")
会产生83MB的空间:
调用上述函数将导致500MB:
为何如此之高的内存使用量是什么原因,我该怎么做才能对其进行优化?
Powershell版本:
Major Minor Build Revision
----- ----- ----- --------
5 1 17134 407
答案 0 :(得分:1)
[System.Net.WebClient]
类型的.DownloadData()
方法返回字节数组([byte[]]
)。
如果您将对该方法的调用的输出直接分配给变量 ,则变量将按以下方式接收该字节数组是 。
相反,如果使用对该方法的调用从函数 中产生隐式输出,则{{1 }} 数组的元素被一个接一个地发送到管道 (逐字节)。
流水线背后的设计意图是启用流,逐个对象处理,而不是收集所有结果优先的行为,这会以执行速度为代价来限制内存,成为输出的一对一处理。
将函数的输出分配给变量,然后使PowerShell 以常规[byte[]]
数组隐式收集单个输出对象(在这种情况下为字节)。
换句话说:原始的[object[]]
数组是首先被枚举的,直到后来被收集在另一个数组中,尽管是[byte[]]
-输入一个-在您的情况下显然是不必要的并且效率低下。
有两种退出此隐式枚举的方法:
您可以使用 概念上明确的 [object[]]
来代替隐式输出,以禁止枚举输出数组(集合):
Write-Output -NoEnumerate
一个比较晦涩的方法,但 更简洁,更快速 的替代方法是将隐式输出与辅助单元素包装器数组< / em> ,这会导致PowerShell仅枚举包装器数组,并通过包装的数组,就像PetSerAl在对问题的评论中所建议的那样:
Write-Output -NoEnumerate (New-Object System.Net.WebClient).DownloadData($UrlCode)
, (New-Object System.Net.WebClient).DownloadData($UrlCode)
是PowerShell的数组构造运算符("comma operator"),并且以其一元形式将RHS封装为单个元素({{ 1}})数组。