storage: zero-copy BidiReadObjectResponse parsing and off-loop CRC32C verification for async multi-range reads
I maintainer di solito rispondono entro 1 giorno
@chandra-siri ci sta già lavorando.
Dal 12/10/2026.
Valutazione
Questa issue non è ancora stata valutata.
Descrizione
Summary of the feature request
AsyncMultiRangeDownloader reads from Rapid (zonal) buckets over the BidiReadObject gRPC stream. Per process, throughput is bound by the asyncio event-loop thread: every 2 MiB BidiReadObjectResponse is processed on that thread, under the GIL, before the next message can be received, and all streams of a process queue behind it.
Profiling one process reading 16 streams at 2.0 GB/s (c4-standard-192, bucket in the same zone, py-spy on the loop thread) gives 318 ms of loop-thread time per GB:
| Step on the loop thread | ms per GB |
|---|---|
| gRPC receive copy | 123 |
BidiReadObjectResponse.deserialize (upb copies the payload: copy 1) |
69 |
checksummed_data.content (proto-plus returns a new bytes: copy 2) |
58 |
google_crc32c.value() inline |
38 |
| asyncio overhead | 30 |
Two of the three large items are avoidable:
- The payload is copied twice by the generated parser. A parser that reads the message in place over the
bytesobject gRPC hands to the deserializer can give the read path amemoryviewof the received message instead (257 us per 2 MiB message today, 5 us in place). - CRC32C verification runs on the loop thread even though
google-crc32calready releases the GIL for inputs of 1 MiB or more; hashing on a small worker pool overlaps it with the next receive.
Both need google_crc32c.value() to accept a memoryview; today it parses its argument with y# and raises TypeError: argument 1 must be read-only bytes-like object, so a view into the gRPC buffer cannot be verified without copying it back to bytes.
Proposed changes (three PRs, independent except that the parser depends on the google-crc32c release):
- #18626
google-crc32c:value()/extend()/Checksum.update()accept any contiguous bytes-like object; the GIL is released forbytes-owned memory of 1 MiB or more (abytesor amemoryviewof one). - #18627
google-cloud-storage: opt-in zero-copy parser,create_mrd(..., zero_copy=True)(orGOOGLE_CLOUD_STORAGE_ZERO_COPY_BIDI_READ=1); only active when the installedgoogle-crc32ccan hash amemoryview, otherwise the generated parser is used. With it on,buffer.write()receives a read-onlymemoryviewof the received message. - #18628
google-cloud-storage: chunks of 1 MiB or more are hashed on a 2-thread pool and written to their buffer only after the checksum matches, in arrival order; on by default,GOOGLE_CLOUD_STORAGE_CRC32C_OFFLOAD_MIN_BYTES=0restores inline verification.
fsspec/gcsfs is the main consumer of this path and would opt in; its sinks copy from the view into the caller's buffer.
Desired code experience
import io
from google.cloud.storage.asyncio.async_grpc_client import AsyncGrpcClient
from google.cloud.storage.asyncio.async_multi_range_downloader import AsyncMultiRangeDownloader
client = AsyncGrpcClient()
mrd = await AsyncMultiRangeDownloader.create_mrd(
client, "my-rapid-bucket", "my-object", zero_copy=True
)
buffers = [io.BytesIO() for _ in range(4)]
# buffer.write() receives memoryview chunks that alias the received gRPC
# message; BytesIO, binary files and bytearray sinks accept them unchanged.
await mrd.download_ranges([(i * 16 << 20, 16 << 20, buf) for i, buf in enumerate(buffers)])
Off-loop verification needs no code change; it applies to download_ranges with enable_checksum=True.
Expected results
Same machine and bucket, 16 streams per process, 4 x 16 MiB per download_ranges call into preallocated buffers, CRC32C verification on, aggregate GB/s:
| Processes | main |
zero-copy parser (#18627, median of 3 interleaved runs) | off-loop CRC32C (#18628, median of 9) |
|---|---|---|---|
| 1 | 1.55 | 2.62 | about 2.0 for both arms (unchanged) |
| 8 | 9.76 | 11.29 | 8.17 -> 9.59 (+17%, led in 7 of 9 paired runs) |
With all three changes together, one process goes from 1.6 to 3.5 GB/s and eight processes from 9.8 to 13.5 GB/s; loop-thread time per GB drops from 318 ms to 195 ms.
Environment: google-cloud-storage at 053dbc9872ad, google-crc32c 1.9.0 (main arm), grpcio 1.84.0, protobuf 7.36 (upb backend), Python 3.13, c4-standard-192 in us-central1-c.
- Lingua principale
- Python
- Stelle
- 5.4k
- Fork
- 1.8k
- Merge medio
- 2g 7h
- PR unite (30g)
- 173
Preparare l'ambiente
- 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 googleapis/google-cloud-python
-
firestore: field path with a quoted name ending in a backslash is misparsedForse già presa @sebxt l’ha presa 25 giorni fa. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
googleapis/google-cloud-python#18771 ·
I maintainer di solito rispondono entro 1 giorno
-
api: spanner type: feature request
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
googleapis/google-cloud-python#18584 ·
I maintainer di solito rispondono entro 1 giorno
-
auth: `impersonated_credentials` loses `subject` on copy, so `with_scopes()` and `with_quota_project()` turn off domain wide delegationForse già presa @Om-singhaI l’ha presa 55 giorni fa. Apertaauth priority: p2 type: bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 88/100
googleapis/google-cloud-python#18428 ·
I maintainer di solito rispondono entro 1 giorno
-
A client called `run_in_transaction` be stuck if Spanner is downForse già presa @founderinaction l’ha presa 7 giorni fa. Apertapriority: p2 type: bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
googleapis/google-cloud-python#18375 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
ci: enable --strict flag in presubmit twine_checkForse di nuovo libera @ohmayr l’ha presa 44 giorni fa e non c’è nessuna pull request aperta. Aperta
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 76/100
googleapis/google-cloud-python#18339 · 1 commento · 1 assegnatario ·
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di googleapis/google-cloud-python
Issue simili
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 62/100
cpp-best-practices/project_validator#267 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
Project-N-E-K-O/N.E.K.O#3725 ·
I maintainer di solito rispondono entro 1 giorno
-
[Bug] Sending a Telegram message chain twice duplicates mentionsForse già presa @123XieC l’ha presa oggi. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
AstrBotDevs/AstrBot#11125 ·
I maintainer di solito rispondono entro 1 giorno
-
backend bug priority: high
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
nooriegarg/ContribIQ#73 ·
I maintainer di solito rispondono entro 1 giorno
-
bug p3 security
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
I maintainer di solito rispondono entro 1 giorno