tarfile: extractfile(member).read() of a sparse member is slow due to repeated bytes concatenation
I maintainer di solito rispondono entro 1 giorno
@devdavidejesus ci sta già lavorando.
Dal 29/10/2026.
Valutazione
- Difficoltà
- 2/5
- Tempo stimato
- 1-3 ore
- Idoneità per principianti
- 75/100
Direzione di ricerca
Leggi _FileInFile.read() in Lib/tarfile.py e segui il modo in cui aggiunge segmenti di dati e buchi sparsi. Controlla i test tarfile esistenti per i membri sparsi, poi aggiungi test per extractfile().read() e per le letture a blocchi, verificando il contenuto atteso. Il lavoro è completato quando entrambi i pattern di lettura restituiscono il contenuto corretto e la lettura completa evita concatenazioni ripetute di bytes.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Bug report
_FileInFile.read() in Lib/tarfile.py builds its result with buf += b for each data segment and buf += NUL * length for each hole of a sparse member. Each bytes concatenation copies the whole accumulated buffer, so reading a sparse member with TarFile.extractfile(member).read() takes time proportional to the member size times the number of sparse segments.
Holes take no space in the archive, so a small archive is enough to make this noticeable. extract(), extractall() and reading the member in small chunks (for example with shutil.copyfileobj()) are not affected.
Reproducer
import io, tarfile, time
def build(n, blk=4096):
# GNU sparse 0.1 (pax) member: n data blocks separated by holes.
t = tarfile.TarInfo("GNUSparseFile.0/a.img")
t.size = n * blk
t.pax_headers = {
"GNU.sparse.map": ",".join(f"{2 * i * blk},{blk}" for i in range(n)),
"GNU.sparse.name": "a.img",
"GNU.sparse.realsize": str(2 * n * blk),
}
bio = io.BytesIO()
with tarfile.open(fileobj=bio, mode="w", format=tarfile.PAX_FORMAT) as tf:
tf.addfile(t, io.BytesIO(b"D" * t.size))
return bio.getvalue()
def read_time(n):
with tarfile.open(fileobj=io.BytesIO(build(n))) as tf:
f = tf.extractfile(tf.next())
t0 = time.perf_counter()
f.read()
return time.perf_counter() - t0
for n in (1000, 2000, 4000):
print(f"{n} segments: {read_time(n):.2f}s")
On a release build (macOS, Apple M3) the read of a sparse member with 4000 segments takes several seconds; the time roughly quadruples when the segment count doubles. With the change below each read is a fraction of a second.
Suggested fix
Accumulate the pieces in a list and join once, instead of repeated concatenation:
- buf = b""
+ chunks = []
while size > 0:
...
- buf += b
+ chunks.append(b)
else:
- buf += NUL * length
+ chunks.append(NUL * length)
size -= length
self.position += length
- return buf
+ return b"".join(chunks)
I have a branch with this change and a regression test that reads a multi-segment sparse member through extractfile().read() and in chunks, and compares both to the expected content. I can open a PR if this looks right.
- Lingua principale
- Python
- Stelle
- 77.8k
- Fork
- 37.7k
- Merge medio
- 11h 25m
- PR unite (30g)
- 723
Preparare l'ambiente
Avvia il container di sviluppo del progetto nel browser, con il tuo account GitHub.
- Nessun Dockerfile né file Docker Compose
- Ha un modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di python/cpython
-
Null dereferencing of a pointer in initconfig.cForse già presa @lazerg l’ha presa 1 giorno fa. Apertainterpreter-core topic-C-API type-bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
python/cpython#160962 · 4 commenti ·
I maintainer di solito rispondono entro 1 giorno
-
tests topic-profiling type-bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
python/cpython#160881 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
3.16 build pending type-bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 62/100
python/cpython#160829 · 5 commenti ·
I maintainer di solito rispondono entro 1 giorno
-
dependencies infra topic-ensurepip
Difficoltà 2/5 1-3 ore Idoneità per principianti 66/100
I maintainer di solito rispondono entro 1 giorno
-
symtable: repr() of a Symbol raises TypeError under -X lazy_imports=allForse già presa @anistark l’ha presa 2 giorni fa. Apertastdlib topic-lazy-imports type-bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
python/cpython#160810 · 4 commenti ·
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di python/cpython
Issue simili
-
Bug: POWERTOOLS_IDEMPOTENCY_DISABLED set to an empty or non-boolean value crashes every invocationForse già presa @lechakrawarthy l’ha presa oggi. Apertabug good first issue help wanted idempotency
Difficoltà 2/5 1-3 ore Idoneità per principianti 85/100
aws-powertools/powertools-lambda-python#8728 · 2 commenti ·
I maintainer di solito rispondono entro 2 giorni
-
bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 85/100
emeraldleaf/okl#320 ·
I maintainer di solito rispondono entro 1 giorno
-
bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 80/100
mnemosyne-oss/mnemosyne#1309 ·
I maintainer di solito rispondono entro 1 giorno
-
bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 70/100
huggingface/diffusers#15163 ·
I maintainer di solito rispondono entro 1 giorno
-
integration: ring
Difficoltà 2/5 1-3 ore Idoneità per principianti 85/100
home-assistant/core#189787 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno