Performance 下载文件时HttpWebRequest性能不佳

Performance 下载文件时HttpWebRequest性能不佳,performance,powershell,download,httpwebrequest,webclient,Performance,Powershell,Download,Httpwebrequest,Webclient,在阅读了很多文章之后,我似乎没有找到我的问题的答案——所以我来了 使用HttpWebRequest只需下载一个文件,它的性能非常慢,似乎限制在1.5-2Mbps左右 另一方面,WebClient.DownloadFile的性能很好,通过浏览器下载也很好 我正试着把我的头脑集中在正在发生的事情和我错过的事情上。我正在Powershell中编写代码,因此可能存在一些问题 我想使用HttpWebRequest,以便通过下载保持控制,并跟踪进度,因为我将处理一些30-70+GB的非常大的文件 非常简单地

在阅读了很多文章之后,我似乎没有找到我的问题的答案——所以我来了

使用HttpWebRequest只需下载一个文件,它的性能非常慢,似乎限制在1.5-2Mbps左右

另一方面,WebClient.DownloadFile的性能很好,通过浏览器下载也很好

我正试着把我的头脑集中在正在发生的事情和我错过的事情上。我正在Powershell中编写代码,因此可能存在一些问题

我想使用HttpWebRequest,以便通过下载保持控制,并跟踪进度,因为我将处理一些30-70+GB的非常大的文件

非常简单地说,我有以下代码片段,为了简单起见,我编写了一个内存流,使用了常见的111MB Nvidia下载,并包含了一些性能测量逻辑:

$Buffer = New-Object -TypeName "Byte[]" -ArgumentList 65536
$FilePath = "e:\temp\test.exe"
$Request = [System.Net.HttpWebRequest]::Create("https://download.nvidia.com/gfnpc/GeForceNOW-release.exe")
$Request.set_Timeout(15000)
$Response = $Request.GetResponse()
$TotalLength = $Response.get_ContentLength()
$TotalLengthKB = [System.Math]::Floor($Response.get_ContentLength()/1024)
$ResponseStream = $Response.GetResponseStream()
$TargetStream = New-Object System.IO.MemoryStream
$TargetStream.SetLength($TotalLength)

$DownloadBytes = 0
$DownloadKB = 0
$ObservedCounts = @{}
$StopWatch = New-Object System.Diagnostics.Stopwatch
$StopWatch.Start()

Try {
    Do {
        # Fill download buffer for this request
        $Count = $ResponseStream.Read($Buffer, 0, $Buffer.Length)

        If ($ObservedCounts.ContainsKey($Count)) {
            $ObservedCounts[$Count]++
        } Else {
            $ObservedCounts[$Count] = [Int32]1
        }

        # Update downloaded bytes and progress for this request
        $DownloadedBytes = $DownloadedBytes + $Count
        $DownloadedKB = [System.Math]::Floor($DownloadedBytes/1024)
        $Progress = [System.Math]::Floor($DownloadedKB / $TotalLengthKB * 100)

        Write-Progress -Activity "Downloading" -Id 1 -PercentComplete $Progress -Status "Downloaded $($DownloadedKB) KB of $($TotalLengthKB) KB"

        # Write data to the file for this request.
        $TargetStream.Write($Buffer, 0, $Count)

    } Until ($Count -eq 0 -or $StopWatch.Elapsed.Seconds -ge 15)

    Write-Host "Done"
} Catch {
    # There was an error during processing of this request
    Throw $_
} Finally {
    if ($TargetStream.CanWrite) {
        $TargetStream.Flush()
        $TargetStream.Close()
    }

    $TargetStream.Dispose()
    $ResponseStream.Dispose()
    
    $StopWatch.Stop()

    Write-Host ('Stopped after {0}' -f $StopWatch.Elapsed.ToString())
    Write-Host ('Downloaded: {0} KB' -f $DownloadedKB)
    Write-Host "Observed Counts:"
    @($ObservedCounts)|Sort-Object Value -Descending|Format-Table|Out-String -Stream
}
15秒后,下载停止,并显示统计信息:

PS E:\temp> .\test.ps1
Done
Stopped after 00:00:15.0142467
Downloaded: 17407 KB
Observed Counts:

Name                           Value
----                           -----
16383                          1088
16                             67
3                              2


PS E:\temp>
与WebClient.DownloadFile()相同的文件:

其中,一个简单的WebClient.DownloadFile()在大约7秒钟内完成111MB的下载,而HttpWebRequest只需15秒钟,我几乎无法管理17MB

我怀疑ResponseStream中的.Read似乎忽略了缓冲区大小,因为它在大多数情况下返回16383字节-它实际上并不关心我将缓冲区设置为什么大小,除非我将其降低到16383字节以下

我尝试在读/写流之间放置一个BufferedStream,但实际上没有改变任何事情

我做了很多Powershell脚本编写工作,经常使用.NET类,但对C#或其他.NET“真实”语言并不熟练,因此我很可能正在做一些我根本看不到的新手,所以希望一个友好的灵魂能帮助我发现我的错误

这显然是我的代码中的一些东西,因为WebClient在后台使用相同的类,并且工作得足够好


提前感谢。

对于这些应用程序,我肯定会使用BITS。 是可靠的,你可以控制油门

在:

1)您的奇数缓冲区大小将导致硬件缓存行为不佳(将其增加到65536),2)
写入进度缓慢,请将其删除:)也许使用可以加快速度。在写入内存流时,请查看
-Asynchronous
开关,这也可能导致30-70gb文件出现问题,虽然您可以通过使用接受
容量
参数的构造函数稍微提高性能,这样就不必在其大小增加时保留额外的内存@MathiasR.Jessen缓冲区大小应该已经是这个大小(输入错误-我会更新问题)-并且-写进度是用来跟踪进度的-我已经尝试过了,现在没有它,这没有任何区别。@mclayton MemoryStream仅在这方面用于简化,以消除其他地方可能出现的瓶颈(我不会将30GB以上的文件下载到内存流中)。在代码中,当我检索到内容的大小时,MemoryStream会在初始请求之后调整到最终大小,因此大小不会持续增加。
PS E:\temp> Measure-Command {$WebClient.DownloadFile("https://download.nvidia.com/gfnpc/GeForceNOW-release.exe", "e:\temp\blah.exe")}
Days              : 0
Hours             : 0
Minutes           : 0
Seconds           : 7