Repository navigation
Progress bar can significantly impact cmdlet performance #2138
Description
Activity
How can you be sure that it's the progress bar? With
$ProgressPreference = 'SilentlyContinue', you can suppress the progress bar UI, which will surely boostInvoke-WebRequest. Also, use-UseBasicParsingwhen downloading files withiwr(which you shouldn't do since that's not whatiwris for...). You cannot suppress parsing, but you can suppress DOM parsing.Moreover, I did your tests and found that the standard deviation is rather great (poor network here in China).
Please do observe Task Manager for the network speed and also do more statistics. If the network is perfect (I hosted a file locally and tried to download via
localhost, all three were superfast even the file is 80MB+, with progress bar suppressed.)And, could you include the
$PSVersionTable?SteveL-MSFT commented
on Aug 31, 2016 MemberAuthorMore actionsPSEdition Core
CLRVersion
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
BuildVersion 3.0.0.0
GitCommitId v6.0.0-alpha.9
PSRemotingProtocolVersion 2.3
PSVersion 6.0.0-alpha
WSManStackVersion 3.0
SerializationVersion 1.1.0.1- addedIssue-BugIssue has been identified as a bug in the productIssue has been identified as a bug in the productWG-Cmdletsgeneral cmdlet issuesgeneral cmdlet issues
on Sep 1, 2016 I also see the progress bar slowing down Invoke-WebRequest by >50X on a fast internet connection. Every time I write a script that uses Invoke-WebRequest I need to include code to temporarily change
$ProgressPreference, then restore it later (because I do want progress for other things).Here's my output from using Invoke-WebRequest to download the same file as Steve Lee (@SteveL-MSFT), without and then with progress:
PS D:\> $ProgressPreference = 'SilentlyContinue' PS D:\> Measure-Command { Invoke-WebRequest "https://github.com/dotnet/corefx/archive/master.zip" -OutFile "D:\temp\master.zip" } Days : 0 Hours : 0 Minutes : 0 Seconds : 6 Milliseconds : 72 Ticks : 60729893 TotalDays : 7.02892280092593E-05 TotalHours : 0.00168694147222222 TotalMinutes : 0.101216488333333 TotalSeconds : 6.0729893 TotalMilliseconds : 6072.9893 PS D:\> $ProgressPreference = 'Continue' PS D:\> Measure-Command { Invoke-WebRequest "https://github.com/dotnet/corefx/archive/master.zip" -OutFile "D:\temp\master2.zip" } Days : 0 Hours : 0 Minutes : 6 Seconds : 11 Milliseconds : 664 Ticks : 3716642777 TotalDays : 0.00430166988078704 TotalHours : 0.103240077138889 TotalMinutes : 6.19440462833333 TotalSeconds : 371.6642777 TotalMilliseconds : 371664.2777 PS D:\> $PSVersionTable Name Value ---- ----- PSVersion 5.1.14931.1000 PSEdition Desktop PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...} BuildVersion 10.0.14931.1000 CLRVersion 4.0.30319.42000 WSManStackVersion 3.0 PSRemotingProtocolVersion 2.3 SerializationVersion 1.1.0.1It would be nice to be able to have reasonable progress when downloading a file. Perhaps if there were a way to adjust the progress reporting interval to several KB instead of every byte (!!) then the overhead wouldn't be so bad.
This issue also affects Expand-Archive. For a large archive (10 MB with 3495 files), expanding it takes over 4X long with progress compared to without.
- changed the title
[-]Invoke-webrequest slow at downloading files due to progress bar perf[/-][+]Progress bar can significantly impact cmdlet performance[/+]on Oct 4, 2016 Changed title to be a generic issue with the progress bar.
Yeah, this is pretty bad ...
Duration CommandLine -------- ----------- 0.0356085s 1..1e3 | % { $null } 0.7734768s 1..1e3 | % { Write-Host "..." } 4.8700151s 1..1e3 | % { Write-Progress "..." } 0.0040193s $ProgressPreference = "SilentlyContinue" 0.0573198s 1..1e3 | % { Write-Progress "..." }Reacted by Jens- addedWG-Engine-Performancecore PowerShell engine, interpreter, and runtime performancecore PowerShell engine, interpreter, and runtime performance
on Oct 17, 2016 I remember noticing how much of a blocker progress writing was when I wrote the PSCX GAC provider back in 2007:
foreach (AssemblyName name in Fusion.GetAssemblies(_type)) { ++i; if (i % 5 == 0) { WriteProgress(name.Name); }https://github.com/Pscx/Pscx/blob/master/Src/Pscx/Providers/AssemblyCache/AssemblyNameCache.cs#L79
We decided to only write a record on every fifth iteration.
It's very simple (write a record on every fifth iteration). 👍 Just seems the compromise is not always the optimal.
May be possible to write asynchronously every 3-5 seconds?Ilya (@iSazonov) Yeah. I'm just saying that it's a problem that's been there since the beginning. Skipping records doesn't solve all issues.
Oisin Grehan (@oising) This is not a criticism from me. I just asked your opinion on "async" since you have experience with the problem.
Reacted by Oisin Grehan22 remaining items
Niclas Lindgren (@NiclasLindgren) Thanks for your comment!
ISE is not in the PowerShell Core repo, it is not ported and no plans is.NiclasLindgren commented
on Jul 12, 2017 More actionsYes, my point was, that "powershell for windows" (v4.0) has the same problem, When run under ISE the "console" does not slow down the performance, I thought it might be interesting for those with access to ISE to check what they do. Either way, the solution discussed here helped and I am happy =)
Niclas Lindgren (@NiclasLindgren) Welcome to test PowerShell Core Beta.4! We have some console fixes in last time from Jason Shirk (@lzybkr) so you may be surprised how much the console is faster. Also we wait a feedback for loading and using Windows PowerShell modules in PowerShell Core Beta.4.
Niclas Lindgren (@NiclasLindgren) the long and short of it is that rendering progress bars in WPF is orders of magnitude fast than drawing progress bars in the windows console. It's not about the code path per-se.
SteveL-MSFT commented
on Jul 13, 2017 MemberAuthorMore actionsNiclas Lindgren (@NiclasLindgren) haven't peeked at the ISE code, but I suspect the progress bar is being rendered on a separate thread while the console uses the same thread
- added a commit that references this issue
on Jan 11, 2019 - added a commit that references this issue
on Jul 20, 2019 - added a commit that references this issue
on Jun 10, 2020 Hello folks!
I'm very sorry for digging up this old issue again, but I had to notice it still seem to be unresolved 6 years later.I ran my test using
Invoke-WebRequestto download a bigger file. With no additional flags or settings, the download speed gets limited to 2-3 MBit/s on my machine - compared to 100 MBit/s+ without the progress bar. This was tested in the stock powershell console delivered with the latest Win11 22H2 update (PSVersion: 5.1.22621.169).As I read above, there is, or used to be a fix. Is it still there?
ThomasNieto commented
on Sep 30, 2022 ContributorMore actionsFlo (@max06) this has already been fixed in PowerShell. Windows PowerShell most likely will never get that fix.
You can get around it on Windows PowerShell by using setting https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_preference_variables?view=powershell-7.2#progresspreference to SilentlyContinue.
Reacted by Flo and Drew McClarenThomas Nieto (@ThomasNieto) Thank you for your quick response!
So, Windows Powershell is different from this one? I never knew that 😲
I'm also not using PS very often, a colleague reported this issue while setting up a new server - I'll forward your hint to him.
- added a commit that references this issue
on Jan 4, 2023 - added a commit that references this issue
on Aug 31, 2026
Repro Steps :
Compare perf of WebClient, BITS and Invoke-WebRequest:
Expected: Transfer speeds don't differ too much (maybe Invoke-WebRequest should be a bit faster than BITS which performs the transfer in background.)
Actual: 10x slowdown for Invoke-WebRequest