Move numpy arrays and metadata between processes blazingly fast!
Project description
ZeroPickleQueue 🚀
ZeroPickleQueue is a high-performance, near drop-in replacement for Python's multiprocessing.Queue, optimized for NumPy arrays.
By leveraging Python's shared_memory module, it eliminates the massive overhead of pickling and unpickling large datasets between processes.
🏎️ Why ZeroPickleQueue?
In standard Python multiprocessing, sending a large NumPy array through a Queue involves:
- Serialization: Pickling the array in the producer process.
- IPC Transfer: Moving the serialized bytes through a pipe.
- Deserialization: Unpickling the array in the consumer process.
For high-resolution video frames (e.g., 4K images), this process can take 50ms–200ms per frame, creating a massive bottleneck. ZeroPickleQueue writes the data to a shared memory block and only passes compact metadata through the queue, reducing transfer latency substantially.
✨ Features
- Near Drop-in Compatibility: API follows
multiprocessing.Queue(put,get,empty,full) with NumPy-first constraints. - Metadata Support: Pass extra info (timestamps, labels) along with your arrays.
- Automatic Resource Management: Includes
atexithandlers to clean up shared memory segments and prevent memory leaks. - Thread-Safe Slot Recycling: Uses a background acknowledgment thread to manage memory slot reuse automatically.
📦 Installation
pip install zeropickle
🛠 Usage
Basic Example
The interface is designed to be familiar to anyone who has used standard Python multiprocessing.
import numpy as np
from multiprocessing import Process
from zeropickle import ZeroPickleQueue
def producer(queue):
# Create a large dummy frame
frame = np.random.randint(0, 255, (2160, 3840, 3), dtype=np.uint8)
queue.put(frame)
queue.put(None) # Sentinel to signal completion
def consumer(queue):
while True:
item = queue.get()
if item is None:
break
print(f"Received array with shape: {item.shape}")
if __name__ == "__main__":
# Define the shape and dtype beforehand
q = ZeroPickleQueue(
data_shape=(2160, 3840, 3),
data_dtype=np.uint8,
max_size=10
)
p1 = Process(target=producer, args=(q,))
p2 = Process(target=consumer, args=(q,))
p1.start()
p2.start()
p1.join()
p2.join()
Passing Metadata
You can pass a tuple where the first element is the NumPy array, and subsequent elements are your metadata.
None is also supported as a sentinel value for graceful consumer shutdown.
Other non-array payloads are not supported.
Compatibility Notes
ZeroPickleQueue is a near drop-in replacement, not a full drop-in replacement.
It keeps the familiar queue methods, but requires fixed data_shape/data_dtype at initialization and only accepts NumPy-array payloads (plus None sentinel).
# Producer
queue.put((image_array, {"frame_id": 42, "detected_objects": 3}))
# Consumer
image, meta = queue.get()
print(meta["frame_id"])
⚙️ How It Works
- Pre-allocation: On initialization, a shared memory segment is created to hold
max_sizearrays of the specified shape. - Slot Tracking: An internal queue manages "slots" (indices) in that memory block.
- The Put Operation: The producer claims a slot, copies the NumPy data into it using
np.copyto, and sends the slot index via a standard queue. - The Get Operation: The consumer reads the slot index, accesses the shared memory, and immediately notifies an "acknowledgment queue."
- Recycling: A background thread monitors acknowledgments and returns used slots back to the producer for reuse.
⚠️ Limitations & Tips
- Fixed Dimensions: Because memory is pre-allocated, every array must match the
data_shapeanddata_dtypeprovided at initialization. - Copy on Get: Currently,
.get()returns a copy of the data. This is safer as it prevents the producer from overwriting memory that the consumer is still reading. - Cleanup: Always call
.close()or rely on theatexithandler to ensure/dev/shm(on Linux) doesn't fill up with orphaned memory segments.
🤝 Contributing
Contributions are welcome! If you have ideas for non-copying reads or support for variable-length data, feel free to open an issue or a PR.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file zeropickle-0.1.0.tar.gz.
File metadata
- Download URL: zeropickle-0.1.0.tar.gz
- Upload date:
- Size: 6.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e953d1ede98cf9d1825acc89bb99bc4e682b19b5c906e4643c0593c0cb5444b5
|
|
| MD5 |
7ffc5cc43e66e644594e36527e66009e
|
|
| BLAKE2b-256 |
dc90c619678bc28cf8ab7f5076a5fdaf52e59c21e97b50848d6e20295eec74a0
|
File details
Details for the file zeropickle-0.1.0-py3-none-any.whl.
File metadata
- Download URL: zeropickle-0.1.0-py3-none-any.whl
- Upload date:
- Size: 6.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
193abdfa4e5435b52420601bdda308f9ecb996a48af8e020bca3ec81c95c7d17
|
|
| MD5 |
ab4bbd4f756d4c68bc5d050ca05f9ead
|
|
| BLAKE2b-256 |
3fe1512ba48e319baa8904a371e4b8401c227c30e8109d9fbf9821e4238a9c9e
|