Skip to content

tarfile "r|*" (stream mode) is much slower than "r:*" #121109

Closed

Description

@TomiBelan

Bug report

Bug description:

Many common operations on tarfile.TarFile are orders-of-magnitude slower when you open it with mode r|* than with the default mode r:*. The better the archive's compression ratio, the bigger the speed difference.

Slow operations include: calling tf.list(); iterating TarInfos in the TarFile without extracting them; extracting with tf.extractall(); extracting with tf.extractfile(info) + shutil.copyfileobj; etc.
In contrast, reading a whole file into memory with extractfile() + f.read() is not affected.

Steps to reproduce

  1. Create test tar files containing 3 files of size 100MB filled with the letter 'x':

    rm -rf data; mkdir data; for i in 1 2 3; do head -c100M /dev/zero | tr '\0' 'x' > data/$i.dat; done
    tar caf test.tar.gz data
    tar caf test.tar.xz data
    tar caf test.tar.bz2 data

    They are quite well compressed from the original size (300MB):

    -rw-r--r-- 1 tomi users 299K Jun 27 23:02 test.tar.gz
    -rw-r--r-- 1 tomi users  46K Jun 27 23:02 test.tar.xz
    -rw-r--r-- 1 tomi users  566 Jun 27 23:02 test.tar.bz2
    
  2. Compare r:* versus r|*:

    import sys, tarfile
    with tarfile.open(sys.argv[1], sys.argv[2]) as tf: tf.list()

Expected results

Both modes should be fast and finish in a few seconds.

Actual results

filename mode time
test.tar.gz r:* 1.013s
test.tar.gz r|* 14.117s (14x slower)
test.tar.xz r:* 0.928s
test.tar.xz r|* 4m44.648s (300x slower)
test.tar.bz2 r:* 0.773s
test.tar.bz2 r|* 23m44.672s (1840x slower)

Root cause

_Stream.dbuf can become very large. Slicing it with self.dbuf = t[size:] is accidentally quadratic™.

Mode r:* uses _compression.DecompressReader instead of tarfile._Stream, which calls self._decompressor.decompress() with a max_length parameter.

I might try to send a pull request if I figure it out.

CPython versions tested on:

3.10, 3.11, CPython main branch

Operating systems tested on:

Linux

Linked PRs

Activity

  1. serhiy-storchaka commented on May 23, 2026

    @serhiy-storchaka
    Member

    @TomiBelan, could you please test how your change affects the case of reading files byte-by-byte or by small chunks.

  2. TomiBelan commented on May 23, 2026

    @TomiBelan
    ContributorAuthor

    Did you mean to comment that in the PR? I'll reply there.

  3. added
    performancePerformance or resource usage
    stdlibStandard Library Python modules in the Lib/ directory
    on May 23, 2026
  4. added a commit that references this issue on May 30, 2026
  5. serhiy-storchaka commented on May 30, 2026

    @serhiy-storchaka
    Member

    This issue is borderline between a bug fix and a feature request. So I will only apply the fix to 3.15+ for now. Users can simply use r:* in older versions.

  6. TomiBelan commented on Jun 1, 2026

    @TomiBelan
    ContributorAuthor

    Thanks for reviewing. 3.15+ is fine by me.

  7. added a commit that references this issue on Jun 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    performancePerformance or resource usagestdlibStandard Library Python modules in the Lib/ directorytype-bugAn unexpected behavior, bug, or error

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions