ShopperCove
Menu
All writingBlogTopicsCategoriesAboutRSS
Blog
Categories
Observability & SRE62All categories
About

Plate 57

  1. Blog

memoryview vs bytes Slice: Localhost Lab

Aditya Challa·1 October 2026·3 min read

Summary
On this page
  1. Intro — what this post promises
  2. Arms
  3. Lab topology
  4. Lead table (p50 ops/s)
  5. Reading it for SRE work
  6. When tobytes matters
  7. Allocation story
  8. Pitfalls
  9. Reproduce
  10. Limits
  11. Takeaway

Intro — what this post promises

Window into a buffer with memoryview vs bytes slicing. This lab reports ops/s on Linux localhost, plus whether the result is a view or a new bytes object.

Related links:

  • shlex vs split localhost lab
  • cmath vs math hypot localhost lab
  • signal vs event wakeup localhost lab
  • path read text vs open localhost lab
  • intenum vs int localhost lab
  • uuid4 vs uuid1 localhost lab
  • platform vs uname localhost lab
  • selectors vs select localhost lab

Lab honesty (1 Oct 2026 IST): Python 3.13.5. Affiliates: 0. Buffer 65536 bytes; window 1024 bytes.

Verdict up front (n=200000): bytes slice ~14645126 ops/s; memoryview slice ~14877648; materialize via tobytes() ~9375358 vs wrapping a bytes slice ~6273259.


Arms

ArmPattern
raw[mid:mid+chunk]bytes slice
mv[mid:mid+chunk]memoryview slice
bytes(raw[...])redundant materialize
mv[...].tobytes()explicit copy from view
index-sum over windowper-byte access

Seven rounds, p50. Contents equal (equal=True); mv slice is a view (mv_is_view=True).


Lab topology

buf=65536 · chunk=1024 · n=200000 · 7 rounds · p50

Script: lab-evidence/141-memoryview-vs-bytes/results/run_lab.py.


Lead table (p50 ops/s)

Armops/s
memoryview slice14877648
bytes slice14645126
memoryview.tobytes9375358
bytes slice materialize6273259
memoryview index-sum203593
bytes index-sum186724

Slice-object creation rates were close; the semantic win is zero-copy views for parsers that only peek.


Reading it for SRE work

  • Protocol parsers / checksum windows → memoryview so you do not copy every header.
  • Need a real bytes to store/hash long-term → .tobytes() once at the boundary.
  • Microbench ops/s alone understate the win — watch allocations under tracemalloc (lab 131) when slicing large payloads in a loop.
  • Do not keep memoryviews into buffers you will mutate/free unsafely.

When tobytes matters

Explicit tobytes() ran at ~9375358 ops/s, faster here than bytes(bytes_slice) double work (~6273259). Prefer: view while parsing; copy once when ownership must detach.

Index walks were similar (~203593 vs ~186724) — pick memoryview for the allocation story, not a huge ALU miracle.



Allocation story

Creating a slice object was cheap for both APIs here (~14877648 vs ~14645126 ops/s). The difference appears when you do it on multi-megabyte payloads thousands of times per request: bytes slices retain full bytes objects; memoryviews share the buffer. Pair this lab with tracemalloc (lab 131) on your real frame sizes before declaring victory.

For socket code, prefer recv_into / writable memoryviews when filling buffers; this post only covers read-only windows into existing bytes.


Pitfalls

  • Assuming every bytes slice is free (it still builds a bytes object).
  • Exporting a memoryview after the underlying buffer is released.
  • Comparing only ops/s without allocation metrics on multi-MB payloads.
  • Confusing this with lab 63 bytes vs bytearray mutability.

Reproduce

python3 lab-evidence/141-memoryview-vs-bytes/results/run_lab.py

Evidence: summary.json, summary.txt.


Limits

One Linux box, 64 KiB buffer, 1 KiB windows. Not numpy memmap, not sock.recv_into benches.


Release memoryviews promptly in finally blocks when wrapping memory-mapped files or shared buffers.

Benchmark with your frame size — 1 KiB windows on 64 KiB buffers are illustrative, not universal.

Document buffer lifetime next to each memoryview producer in the runbook.

Takeaway

memoryview slices (~14877648 ops/s) matched bytes-slice create rates (~14645126) while staying a view. Use memoryview for zero-copy parsing; copy with tobytes() only when you need owned bytes.

pythonmemoryviewbytesslicingperformancezero-copybufferbenchmark

Lab evidence

What I found running this

Ran the packaged localhost lab on Linux with Python 3.13.5. Seven rounds, p50: memoryview slices reached 14,877,648 ops/s versus bytes at 14,645,126, and the view stayed zero-copy; tobytes() made an owned copy. Affiliates: 0.

Notes when a lab post goes up

Occasional email for new hands-on reviews. No sequence and no sponsors.

Related links

  • Plate 82

    shlex.split vs str.split: Localhost Lab

    1 Oct 2026

  • Plate 59

    enum.IntEnum vs int Status Codes: Localhost Lab

    1 Oct 2026

  • Plate 90

    Path.read_text vs open().read: Localhost Lab

    1 Oct 2026

On this page

  1. Intro — what this post promises
  2. Arms
  3. Lab topology
  4. Lead table (p50 ops/s)
  5. Reading it for SRE work
  6. When tobytes matters
  7. Allocation story
  8. Pitfalls
  9. Reproduce
  10. Limits
  11. Takeaway
All writingBlogCategoriesTopicsAboutPrivacyRSS

© 2026 ShopperCove