Skip to content

Write-Progress drops updates if the calls happen too quickly in succession #18848

Closed

Description

Prerequisites

Steps to reproduce

Note: This is a regression from Windows PowerShell and affects both the Minimal and Classic views (selectable via $PSStyle.Progress.View)

$arr = 1..10
$arr | 
  ForEach-Object { 
    [int] $percentComplete = ($_ / $arr.Count) * 100
    Write-Progress -Activity Test -Status "$percentComplete% complete" -PercentComplete $percentComplete
    # !! Without sleeping for a while, the progress display stops updating after the FIRST call.
    # Start-Sleep -Milliseconds 200
  }
Start-Sleep 5 # Ensure that the progress bar stays visible for a while.

Expected behavior

The progress bar should show 100% and stay visible for 5 seconds.

Actual behavior

The progress bar shows 10% - that is, only the first call took effect.

Error details

No response

Environment data

PowerShell Core 7.3.1

Visuals

No response

Activity

  1. SteveL-MSFT commented on Dec 28, 2022

    @SteveL-MSFT
    Member

    I think you're referring to this change #2822 which was taken awhile back. Basically progress isn't updated except once every 200ms. WinPS had the problem that it would update progress EVERY time an update was available. The time rendering to the console impacted performance (classic examples is invoke-webrequest to download a file took much longer). So I think this is considered by-design,.

  2. added and removed
    Needs-TriageThe issue is new and needs to be triaged by a work group.
    on Dec 28, 2022
  3. mklement0 commented on Dec 28, 2022

    @mklement0
    ContributorAuthor

    Steve Lee (@SteveL-MSFT):

    • It's understandable to want to throttle progress updates so as not to unduly impact overall performance.

    • However, I don't think it is acceptable to ignore subsequent updates.

      • Whatever the last update was in the 200-msec. time window should render.

    Consider a long-running task with progress reports whose timing is highly variable / unpredictable, especially during parallel processing (ForEach-Object -Parallel):

    • Say there are bursts of updates followed by long periods of non-updates.
    • If the bursts significantly meant to advance the progress display (in small increments), the long period of non-updates will present a distorted view.
  4. iSazonov commented on Dec 29, 2022

    @iSazonov
    Collaborator

    This API is flexible enough to avoid such effects. The script developer just needs to use this API correctly. There are three phases - initialization, loop update and finalization. In this example, you need to execute "Complete" after the loop to display the correct state.
    We could make PowerShell smarter, but I don't see the point. I consider this API obsolete to invest in it. It would make sense to create something more modern, productive and convenient. All we need is desire and approval :-)

  5. mklement0 commented on Dec 29, 2022

    @mklement0
    ContributorAuthor

    Ilya (@iSazonov), the example scenario in my previous comment illustrates that the API is not flexible enough - calling "Complete" in the middle of a long-running operation is obviously both unexpected and inappropriate.

  6. mklement0 commented on Dec 29, 2022

    @mklement0
    ContributorAuthor

    Optimizing is a laudable goal, as long as it doesn't get in the way of the user's intent.
    Here, it clearly does.
    I haven't looked into the technical challenges, but to me the current behavior is unacceptable.
    If a modern API can remedy this, all the better - assuming it ever sees the light of day.

  7. mklement0 commented on Dec 29, 2022

    @mklement0
    ContributorAuthor

    And come to think of it: using -Completed doesn't display the correct state, it hides the - potentially outdated - progress bar.

  8. iSazonov commented on Dec 29, 2022

    @iSazonov
    Collaborator

    I was talking about a common script that works correctly - init-update-in-loop-fin.
    If we're talking about the body of the loop, as indicated, it makes no sense to update the output on the screen every "microsecond". This not only creates a performance problem but also violates the very concept of "Progress Bar".

  9. SteveL-MSFT commented on Dec 29, 2022

    @SteveL-MSFT
    Member

    I've noticed that many native tools don't actually clear out progress info once complete (and we'd have to change the code to show the last progress update). So that could help with this, but would have its own dissenters.

  10. iSazonov commented on Dec 29, 2022

    @iSazonov
    Collaborator

    I've noticed that many native tools don't actually clear out progress info once complete (and we'd have to change the code to show the last progress update). So that could help with this, but would have its own dissenters.

    What kind of script example are you referring to?

  11. SteveL-MSFT commented on Dec 29, 2022

    @SteveL-MSFT
    Member

    I've noticed that many native tools don't actually clear out progress info once complete (and we'd have to change the code to show the last progress update). So that could help with this, but would have its own dissenters.

    What kind of script example are you referring to?

    Not any script example, I'm referring to native commands that emit their own custom progress. They tend to keep the last progress on the screen rather than clearing it.

  12. 9 remaining items

  13. SteveL-MSFT commented on Jan 6, 2023

    @SteveL-MSFT
    Member

    Michael Klement (@mklement0) I believe individual cmdlets that are part of PowerShell have also had improvements to how often they write progress. However, the perf fix was general such that poorly written scripts and cmdlets would also not incur a perf impact that the author or even user may not have known about.

    It may be possible to cache the last progress update (rather than discard it) and on every 200ms if the last progress rendered isn't the same as the last progress written, then update without incurring a regression in perf. I believe the significant perf impact previous was the time taken to render on the console so doing a bit of progress record comparison, even frequently, might be ok.

  14. iSazonov commented on Jan 6, 2023

    @iSazonov
    Collaborator

    If we talk exclusively about this optimization (although I think we should start the discussion with the progressbar concept), I do not think that something can be done there without significant cost and loss of optimization.
    We do three expensive things at each step:

    1. Creating ProgressRecord
    2. Writing this ProgressRecord to the engine buffer with preprocessing
    3. Rendering
      Now the optimization cuts off steps 2 and 3. To store the "last" ProgressRecord, we will have to do step two and move the thinning to this level. That is, we lose optimization and add complexity.

    If we start with the progressbar concept, however, we can get an implementation that eliminates losses not only in step 2 and 3, but in step one as well!

  15. iSazonov commented on Jan 6, 2023

    @iSazonov
    Collaborator

    If we talk about the progress bar concept, this is the correct PowerShell as an idea.

    If we look PowerShell stream fundamentals we see 5 PowerShell Streams (Output, Error, Warning, Verbose, Debug) and there is no progress bar. Why? Because progress bar is ephemeral thing, it is psevdo-stream.
    We could think of it as sounds or voice messages.
    The main point is that this information does not intersect with real streams in any way, is not accumulated anywhere, and is not stored anywhere. All relevant information must be directed to the actual PowerShell streams.
    If this antipode to real streams did not exist it should have been created!

    Earlier I have already formulated this concept as:

    The only purpose of the progress bar, as the name says, is to inform the interactive user that the long process is ongoing.

    Keys here are "inform", "interactive", "long". It is not to follow these key principles then problems are inevitable.

    The PowerShell implementation of this concept is done in the spirit of PowerShell, implying that it is done as cmdlets.

    But then we see problems in this implementation (much of this is due to a deviation from key principles):

    • it is very expensive, i.e. the cost of creating and displaying the progress bar is too high and can exceed the cost of the main work.
    • it is too vague, which provokes developers to misuse it in violation of the concept, i.e. they try to display significant information in the progress bar, when it should be directed to one (or more) real PowerShell streams.

    Can PowerShell have a less expensive implementation? Sure.
    Could PowerShell be smarter, save the developer from unnecessary work and tricks? Sure.

  16. SteveL-MSFT commented on Jan 9, 2023

    @SteveL-MSFT
    Member

    I think the request is reasonable from a user perspective, but also agree with Ilya (@iSazonov) (as I've also poked around the Progress code) that the current design of the code doesn't lend itself for enabling these types of changes easily without risk of regression/impact nor is it more critical than spending time fixing other functional issues.

  17. iSazonov commented on Jan 9, 2023

    @iSazonov
    Collaborator

    Perhaps we should think about and adopt the concept that will allow us to simplify the code and at the same time increase the possibilities of customization.
    I was installing an update on Exchange Servers today and there is an instructive progress bar - "this operation will take a few minutes", "this operation will take a long time", etc. - no dots, blinks, flickers or anything else superfluous. Definitely they know how to do things right.

  18. mklement0 commented on Jan 9, 2023

    @mklement0
    ContributorAuthor

    That makes sense, Ilya (@iSazonov), but it seems that the only thing needed for that kind of abstract display is to fix the regression from Windows PowerShell (simply don't display a bar if -PercentComplete isn't used, as previously noted).

    As for the optimization: note that my proposal was - expressed in terms of the 3-step model you describe above - to only do step 1 (repeatedly) in a 200-msec. window and then do steps 2 and 3 only once, at the end of that window - but perhaps that indeed complicates things too much, given that that requires the rendering to happen asynchronously.

  19. iSazonov commented on Jan 10, 2023

    @iSazonov
    Collaborator

    given that that requires the rendering to happen asynchronously.

    I was hoping this was possible, but it turns out that the progress bar display is done synchronously and directly from the runspaces.
    Moreover, there is no classic dedicated UI thread, the main thread is conhost (UI) and at the same time runs the main runspace.
    I think some MSFT teams (as well as other developers) would breathe freer and get rid of headaches if pwsh had a dedicated thread for UI and runspaces were detached from threads. (We can only guess how many resources this eats up in Office365.)
    For example, the Exchange Server team migrated code to managed and more so to asynchronous TAP, but obviously other than pwsh related code.
    This seems to be a relic of the old development environment limitations.

  20. microsoft-github-policy-service commented on Nov 15, 2023

    @microsoft-github-policy-service
    Contributor

    This issue has not had any activity in 6 months, if this is a bug please try to reproduce on the latest version of PowerShell and reopen a new issue and reference this issue if this is still a blocker for you.

  21. microsoft-github-policy-service commented on Nov 15, 2023

    @microsoft-github-policy-service
    Contributor

    This issue has not had any activity in 6 months, if this is a bug please try to reproduce on the latest version of PowerShell and reopen a new issue and reference this issue if this is still a blocker for you.

  22. microsoft-github-policy-service commented on Nov 15, 2023

    @microsoft-github-policy-service
    Contributor

    This issue has not had any activity in 6 months, if this is a bug please try to reproduce on the latest version of PowerShell and reopen a new issue and reference this issue if this is still a blocker for you.

  23. microsoft-github-policy-service commented on Nov 22, 2023

    @microsoft-github-policy-service
    Contributor

    This issue has been marked as "No Activity" as there has been no activity for 6 months. It has been closed for housekeeping purposes.

  24. seppo498573908457 commented on Jun 11, 2026

    @seppo498573908457

    Hi. I can see Write-Progress is a lightweight progress indicator, thus the update limiter. I run into this problem too. I have a script that checks ~150 items for changes. If there are no changes, it will go through all of them in about 1 second. But if an item has changes, it can take 15 to 20 seconds to process it. So when scanning items, the current displayed item is "always" wrong if it needs to process something. This can lead to much confusion and panic.

    My workaround is simple. I added a second progress bar with another -Id, that is displayed only when an item needs to be processed. Clean, fast and simple.

    PS. It would be nice to have this update limiter documented in the Write-Progress documentation and propose a second progress bar as a workaround.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions