PyZas!: A Python library for atomic integer operations
Project description
PyZas!: A Python library for atomic integer operations
PyZas is a Python library designed for performing atomic integer operations with the speed and efficiency of a zas! (Inspired by the sudden impact sound 'zas', a Spanish onomatopoeia). PyZas ensures your calculations are executed atomically and safely. Perfect for scenarios requiring quick, thread-safe manipulations.
Installation
You can install PyZas via pip:
pip install pyzas
Usage
The PyZas module implements the following atomic types:
- AtomicInt: An atomic int type
- AtomicLong: An atomic 64-bytes int type
- AtomicULong: An atomic 64-bytes unsigned int type
The three types implement the following functions:
- free_lock_level() -> int: Determines if the atomic object is implemented lock-free
- load() -> int: Reads a value from an atomic object
- store(int): Stores a value in an atomic object
- exchange(int) -> int: Atomically replaces the value in an atomic object
- fetch_add(int) -> int: Performs atomic addition
- fetch_sub(int) -> int: Performs atomic subtraction
- compare_exchange(int, int) -> int: Swaps a value with an atomic object if the old value is what is expected, otherwise reads the old value
Module also implements AtomicFlag with support for spinlock:
- test_and_set() -> bool: sets an atomic flag to true and returns the old value
- clear(): Sets the atomic_flag to false
- spin_lock(): Causes a thread trying to acquire a lock to simply wait in a loop ("spin")
- spin_unlock(): Releases the lock
For more details:
help(pyzas)
Example
import pyzas
n = pyzas.AtomicInt(0)
n.fetch_add(1)
print(n.load())
Performance Test
from multiprocessing.pool import ThreadPool
import threading
import time
import sys
import pyzas.pyzas as pyzas
def main(threads, its):
e = 0
atomic_e = pyzas.AtomicInt()
lock = threading.Lock()
def test_lock(i):
nonlocal e
with lock:
e = e + 1
def test_atomic(i):
atomic_e.fetch_add(1)
start = time.time()
with ThreadPool(threads) as p:
list(p.map(test_lock, range(its)))
print("Testing with lock", e, time.time() - start)
start = time.time()
with ThreadPool(threads) as p:
list(p.map(test_atomic, range(its)))
print("Testing atomic ", atomic_e.load(), time.time() - start)
if __name__ == '__main__':
if len(sys.argv) < 3:
print(f"Use: python3 {sys.argv[0]} [threads] [its]", file=sys.stderr)
exit(-1)
main(int(sys.argv[1]), int(sys.argv[2]))
Build from sources
Library is built using Poetry:
poetry build
Or to install the library with pip:
pip install .
PYZAS_CFLAGS environment variable can be used to add compilation options.
export PYZAS_CFLAGS="-O2"
poetry build
Most common errors
- Visual Studio still has experimental support for atomics, so we need to enable it to compile the code.
SET PYZAS_CFLAGS=/std:c11 /experimental:c11atomics
poetry build # or pip install .
- cp313 version (with GIL) is being compiled instead of the cp313t version (free-threaded)
If your version has been compiled with GIL, even if you have the free-threaded binaries, it's possible that the build is done for the GIL version. The build tools are still experimental, and don't have a way to fix the compile option, so we have to do it manually.
export PYZAS_FIX_GIL=1 # Linux or MacOS
SET PYZAS_FIX_GIL=1 # Windows
If you want to install using the wheel, you'll need to add t after the version number. For example, pyzas-1.0-cp313-cp313-win_amd64.whl should be pyzas-1.0-cp313-cp313t-win_amd64.whl.
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 Distributions
Hashes for pyzas-1.0.1-cp313-cp313t-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | b1e63868735e4752107f73843c602acb7d7996cc02626eb3e9717bd106990b1e |
|
MD5 | 1275fb070dadbfee4ba7f91022c9cf4c |
|
BLAKE2b-256 | a64b30f557832ec8aac7eecef8aa3b91f60ad99f6883a54d9b2bcb1d656158f8 |
Hashes for pyzas-1.0.1-cp313-cp313t-manylinux_2_31_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | e14b4b0ba14d567c3579d82c6ad18db156f4d571a202a53c120cde04d7fac258 |
|
MD5 | 46cd911d74810a0cf0aec12d31092419 |
|
BLAKE2b-256 | 3743f50df0c85aa8a371e8256818d933ef23a7dd4be3ecaec74a863188b5b7b1 |
Hashes for pyzas-1.0.1-cp313-cp313t-manylinux_2_31_aarch64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | a5e125052c534d72904bc837cfda9dc1d1f06bc4e782e62d21ea3d079e39dbae |
|
MD5 | 939692ecb4cc13999e955953bb432956 |
|
BLAKE2b-256 | f9c787433383aca619652c6770fefad906ba879e8bd43351294c652da6cf3b2c |
Hashes for pyzas-1.0.1-cp313-cp313t-macosx_13_0_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | f836b9b70a3d197aa5f3fb9b9f9c8f80bb266a08bab87aab4e04fbe8f44b6e44 |
|
MD5 | c102b612796f567a30abce65661e40c9 |
|
BLAKE2b-256 | 80cf60efaa772c293129306b311d392445269195422cbd1398a79a8e1147b642 |