ZProc - Process on steroids
Project description
ZProc - Process on steroids
Multi-Processing how it should've been.
If you're wondering, ZProc is short for Zero Process
Philosophy
History
Traditional Multi Processing was mostly, built on the principle of shared memory.
This might sound odd, but shared memory violates the laws of Physics itself.
Don't believe me? watch this (from Joe Armstrong, the creator of Erlang)
The solution presented by Erlang, (and ZMQ) is the notion of message passing for achieving parallelism, or at least concurrency.
Yes, they are different things.
Now
Message passing can be tedious, and often un-pythonic.
This is where ZProc comes in.
It provides a middle ground between message passing and shared memory.
It does message passing, without you ever knowing that it's doing it.
It provides you a global dict
which we like to call state
.
The state
is not shared memory, and works purely on message passing.
If you're a CS majaor, you might recognize this as the Actor Model.
ZProc doesn't blindly follow it, but it you can think of it as such.
The zen of zero
generally, "zero" refers to the culture of minimalism that permeates the project. We add power by removing complexity rather than by exposing new functionality.
Install
pip install zproc
License: MIT License (MIT)
Requires: Python >=3.5
Documentation
Examples
A great way to see zproc in action is through the examples
They should be pretty self-explanatory.
Features
-
🌠 Global State
- Globally synchronized state (
dict
), without using shared memory. - 🔖
- Globally synchronized state (
-
🌠 Asynchronous paradigms without
async def
- Build any combination of synchronous and asynchronous systems.
- watch for changes in state, without Busy Waiting.
- 🔖
-
🌠 Process management
- Process Factory
- Remembers to kill processes when exiting, for general peace. (even when they're nested)
- Keeps a record of processes created using ZProc.
- 🔖
-
🌠 Atomic Operations
- Perform an arbitrary number of operations on state as a single, atomic operation.
- 🔖
Atomicity
The elephant in the room, race-conditions.
In ZProc world, a single dict operation is guaranteed™ to be atomic.
But, in real world applications require arbitrary number of operations to be atomic.
Exhibit A
def increment(step):
state.count += step
increment(5)
increment()
might look like a single operation, but don't get fooled! (They're 2)
-
__getitem__
-> get'count'
-
__setitem__
-> set'count'
to<count> + 1
__getitiem__
and __setitem__
are guarateed™ to be atomtic on their own, but NOT in conjunction.
If these operations are not done atomically, it exposes the possiblity of other Processes trying to do operations between "1" and "2"
Clearly, a remedy is required.
With ZProc, it's dead simple.
Let's make some changes to our example..
@state.atomify()
def increment(state, step):
state.count += step
increment(5)
If it wasn't clear, @state.atomify()
makes any arbitrary function, an atomic operation on the state.
Caveats
- The state only gets updated if you do it directly. This means that if you mutate objects inside the state, they wont get updated in global state.
- It runs an extra daemonic server for managing the state. Its fairly lightweight though, and shouldn't add too much weight to your application.
- The state should be pickle-able
- Missing state updates when using
state.get_when_*
, if updates are too fast.- Current API is not intended for this type of use-case.
- Work is being done to expose new API that will allow you to watch for every singe update, no matter when they occur
FAQ
- fast?
- plenty, since its written with ZMQ.
- See
luck_test.py
example for a taste.
- stable?
- The project itself is stable, but the API is NOT.
- real?
- YES. It works.
- 🔖
- Windows / Mac compatible?
- I honestly don't know. Please tell me.
Inner Workings
-
The process(s) communicate over zmq sockets, over
ipc://
. -
Zproc runs a zproc server, which is responsible for storing and managing the state.
- update the state whenever another process updates it.
- transmit the state whenever a process needs to access it.
-
Overall, the zproc server helps create an illusion of a global shared state when actually, it isn't shared at all!
-
If a process wishes to synchronize at a certain condition, it can attach a handler to the zproc server.
- The zproc server will check the condition on all state-changes.
- If the condition is met, the zproc server shall open a tunnel to the application and send the state back.
- zmq sockets block your application until that tunnel is opened.
Local development
git clone https://github.com/pycampers/zproc.git
cd zproc
pipenv install
Build documentation
Assuming you have sphinx installed (Linux)
cd docs
pipenv run ./build.sh
Thanks
- Thanks to pieter hintjens, for his work on the ZeroMQ library and for his amazing book.
- Thanks to tblib, ZProc can raise First-class Exceptions from the zproc server!
- Thanks to psutil, ZProc can handle nested procesess!
🐍🏕️
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
Hashes for zproc-0.3.2-py2.py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 8fddc3b1dfedd6a340bb9044877a4e250b6a5d541760d65008910db5503fe97f |
|
MD5 | 90a615851a999b112af1055343e7738e |
|
BLAKE2b-256 | 5675a1f203ff9b346c88066c7537b4bb25d698da1bdad1678e81f97993a8da46 |