# progressbar2: measuring the per iteration cost of drawing a bar

> progressbar2 is a BSD licensed Python progress bar whose README argues the case with a benchmark race rather than adjectives, comparing per iteration overhead across six libraries and offering an optional native counting accelerator. The judgement is that the measurement is the interesting part, and that the headline claim in the README should be read as the project's own claim rather than a settled fact.

**wolph/python-progressbar** — Progressbar 2 - A progress bar for Python 2 and Python 3 - "pip install progressbar2"

- Repository: https://github.com/wolph/python-progressbar
- Website: http://progressbar-2.readthedocs.org/en/latest/
- Stars: 879 · Forks: 107
- Language: Python
- License: BSD-3-Clause
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/wolph-python-progressbar

## The benchmark race that the README leads with

The first thing the README argues is that wrapping a fast loop in a progress bar can cost more than the loop itself, so the overhead per iteration is the number that matters. It then replays the measured wall clock times of the same 1,000,000 iteration loop, wrapped with each library's default settings, and the table is the argument. progressbar2 with the fast build costs 3.6 ns per iteration and 9.2 ms for the whole loop, rich comes in at 18.2 ns and 23.8 ms, plain progressbar2 at 26.0 ns and 31.5 ms, tqdm at 52.1 ns and 57.6 ms, alive-progress at 243.3 ns and 248.9 ms, and click at 1829.6 ns and 1835.2 ms. Import weight follows the same pattern, with import progressbar costing 1.5 ms where tqdm takes 21.6 ms and rich 45.6 ms, which the README notes your command line tools will notice. The tagline above all of this calls the library the fastest progress bar in Python, and that is the project's own claim rather than something the repository establishes on its own.

## The fast extra is a native counting iterator

The difference between the 3.6 ns row and the 26.0 ns row is the optional accelerator, and the mechanism is specific. The fast row corresponds to pip install 'progressbar2[fast]', an optional C iterator from the speedups package that counts natively and only calls back into Python when the bar actually needs a redraw. That is the whole trick, and it is the reason the per iteration cost collapses, since a pure Python implementation has to execute bytecode on every item whether or not the bar redraws. The installation is two lines, and the choice is explicit:

```sh
pip install progressbar2           # pure Python
pip install 'progressbar2[fast]'   # adds the native accelerator
```

The README also notes that a plain install runs the pure-Python gate at 26 ns, which it still calls twice as light as tqdm. That gate is the update frequency of the display, so a slower gate means fewer redraws, and the design lets you trade display smoothness against per item cost.

## Read the numbers with the caveat attached

The README is unusually honest about the limits of its own benchmark, and the caveat is printed directly above the table. These numbers come from one machine, an Apple Silicon with CPython 3.13, with output to a real pty rather than a pipe, and from that exact test, measured by benchmarks/bench.py. The README then says plainly that your numbers will differ, and it explains one oddity in the table, that click is measured but left out of the race animation because its 1.8 second total would flatten every other lane. Reproduction is a single command, python benchmarks/bench.py, with the full details in benchmarks/report.md. Two things follow for an adopter. The pty detail matters, since a bar that detects a pipe instead of a terminal may take a different code path, so a benchmark that writes to a pipe is not the same measurement. And the relative ordering is a hypothesis to check on your platform rather than a number to design around.

## The common case is one line around the iterable

The quick start is the smallest possible integration, one call that wraps an iterable and hands the items back:

```python
import time
import progressbar

for item in progressbar.progressbar(range(100), desc='Loading'):
    time.sleep(0.02)
```

What you should see is a bar that advances as the loop runs, and nothing else in your code changes. The documentation is hosted on readthedocs, and the README points out that every snippet in it runs live in the page, so you can press Run on any code block with no install at all. That is a small detail, but it is a real difference from a project whose documentation is a set of screenshots. The repository keeps the source under a progressbar directory, the documentation under docs, the benchmark harness under benchmarks, the tests under tests, and there is a tox.ini, a pytest.ini, a ruff.toml and a pre-commit configuration at the top level.

## Widgets, gradients and several bars at once

The display side is built from widgets, and the README shows three styled bars sharing a terminal through a MultiBar object. A bar can carry a colour gradient that shifts with progress, a fixed colour, or an animated marker. The pieces are imported from two modules, with ColorGradient and the colour names from progressbar.terminal and TGradientColors from progressbar.widgets, and the bars themselves are assembled from widgets such as Percentage, Bar and AnimatedMarker. The scan bar in that snippet is created with a max value of progressbar.UnknownLength, which is how a spinner handles work whose size is not known in advance. Several bars are then updated in a loop and each one is finished at the end, and the sleep in that snippet is deliberately longer than the bars' 0.05 second update gate so that every step lands as a visible redraw. The design point is that MultiBar writes to a single file descriptor, so several independent processes or threads can share one terminal without fighting over the cursor.

## redirect_stdout keeps log lines above the bar

Anything a program prints while a bar is running would normally tear the bar apart, since the bar owns the last line of the terminal and a stray print statement writes over it. The documented fix is redirect_stdout, which routes that output cleanly above the bar instead of through it. This is a small feature with a disproportionate effect on whether a progress bar is usable in a real tool, since almost every real tool logs something while it works, and the usual result of a bar and a log line is a corrupted display. The README demonstrates it with a build log printing above a running bar. The other place output matters is the terminal detection, which is why the benchmark explicitly used a real pty, since a program running under a pipe, such as a CI runner, may not be able to draw a bar at all.

## Packaging, licence and the state of the repository

The distribution story is conventional and the licence is permissive, with the manifest declaring BSD-3-Clause and the repository carrying a LICENSE file. The package on PyPI is progressbar2, and the build backend is setuptools with setuptools-scm required at build time, for a reason the manifest explains in a comment, since its file finder entry point is what populates the source distribution with the full set of git tracked files, and dropping it silently shrinks the sdist and omits the test harness. The version is dynamic and the classifiers describe the project as both Production/Stable and Mature, with environments for the console, macOS, Windows and X11, and frameworks for IPython and Jupyter. Maintenance is the part to check first. The default branch is develop, the last push was on 2026-10-18, the repository is not archived, and the README says the library has been maintained since 2012. The release history shows v4.6.0 on 2026-08-13 after v4.5.0 in August 2024 and v4.4.2 in March 2024, so the recent work is a new minor version after a long gap, and the CI and coverage badges still point at the master branch rather than develop.

## Conclusion

progressbar2 fits a command line tool that wraps a fast loop, where a progress bar can cost more than the work it is reporting, and the optional native accelerator is the reason to prefer it over a heavier bar. It is the wrong choice for a long job where a redraw every few hundred milliseconds is irrelevant, because the overhead argument only bites in tight loops, and it is a poor fit if you want the richer display layer of a full terminal toolkit, since colour and layout here stop at the widget model. Before you adopt it, run benchmarks/bench.py on your own machine rather than trusting the published table, and measure the import cost too, since the README puts import progressbar at 1.5 ms against 21.6 ms for tqdm and 45.6 ms for rich.

## FAQ

### How do I install progressbar2 and the faster native variant?

Run pip install progressbar2 for the pure Python build, or pip install 'progressbar2[fast]' to add the native accelerator, an optional C iterator from the speedups package that counts natively and calls back into Python only when the bar needs a redraw.

### How does progressbar2 compare with tqdm on overhead?

In the README benchmark, progressbar2 with the fast build costs 3.6 ns per iteration and plain progressbar2 costs 26.0 ns, while tqdm costs 52.1 ns for the same million iteration loop. The README notes those numbers come from one machine, an Apple Silicon running CPython 3.13 with output to a real pty, and that your numbers will differ.

### How do I stop log output from breaking a running progress bar?

Use redirect_stdout from the library, which sends anything the program prints to the area above the bar rather than through it. Without it, a print statement during a running bar writes over the bar and corrupts the display.

## Sources

- [License: BSD-3-Clause](https://github.com/wolph/python-progressbar/blob/develop/LICENSE)
- [Project website](http://progressbar-2.readthedocs.org/en/latest/)
- [README](https://github.com/wolph/python-progressbar/blob/develop/README.md)
- [Releases](https://github.com/wolph/python-progressbar/releases)
- [wolph/python-progressbar on GitHub](https://github.com/wolph/python-progressbar)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/wolph-python-progressbar
