• Stars
    star
    119
  • Rank 297,930 (Top 6 %)
  • Language
    Python
  • License
    BSD 3-Clause "New...
  • Created about 10 years ago
  • Updated over 3 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Atomic primitives for Python.

Atomos

Atomic primitives for Python.

Build Status

Atomos is a library of atomic primitives, inspired by Java's java.util.concurrent.atomic. It provides atomic types for bools, ints, longs, and floats as well as a generalized object wrapper. In addition, it introduces atoms, a concept Clojure programmers will be familiar with.

Motivation

Mutable shared state is hard and guess what, it's ubuiquitous in Python. When working in a multi-threaded context or whenever an application is racing, locks can be a useful tool. However they can quickly become unweildy.

To address this, Atomos provides wrappers around primitives and objects which handle the locking semantics for us. These special primitives allow for writing cleaner, simpler code without having to orchestrate locks directly.

In particular Atomos introduces atoms, a new data type for managing shared mutable state. Atoms are a near-direct port of Clojure's eponymous data type. They work by wrapping a given object in compare-and-set semantics.

Installation

Atomos is available via PyPI.

$ pip install atomos

Usage

Say we have some shared state in our application. Maybe we have a chat server which holds state in memory about connected clients. If our application is threaded we will need some way of sharing this state between threads.

We can model this state as an atom. This will ensure that when multiple threads update and retrieve the state, its value is always consistent. For example:

>>> import atomos.atom as atom
>>> state = atom.Atom({'conns': 0, 'active_clients': set([])})

Our state is an Atom, which means we can update it using its swap method. This method works by taking a function which will take the existing state of the atom and and any arguments or keyword arguments we provide it. It should return an updated state.

For instance, as a client connects, we want to update the number of connections and the active client set. We can write a function which we can then pass to swap to safely mututate our state:

>>> def new_client(cur_state, client):
...     cur_state['conns'] += 1
...     cur_state['active_clients'].add(client)
...     return cur_state
>>> state.swap(new_client, 'foo')

Here we have updated our state and can be sure that any other thread which may have looked at the state only ever saw the state as it was before we called swap or after. However any race condition which might have existed between incrementing the connections count and adding the client is eliminated, thanks to our use of the atom.

Atomic Primitives

Atomos also provides atomic primitives as wrappers around int, long, float, and bool as well as a general wrapper around any object type. We can use these primitives to construct a thread-safe counter:

>>> import atomos.atomic
>>> counter = atomos.atomic.AtomicInteger()
>>> counter.get()
0

To increment the counter, we can call counter.add_and_get(1). This will return the new value back to us, 1.

For more complex object types we can use an AtomicReference. For instance, we can wrap any arbitrary class and protect updates to its value like this:

>>> class MyState(object):
...     def __init__(self, foo, bar):
...         self.foo = foo
...         self.bar = bar
>>> state = atomos.atomic.AtomicReference(MyState(42, False))

So long as we interact with the MyState instance via the state wrapper, our updates will always be protected.

Multiprocessing

Now it works with multiprocessing.

Just use the following import path:

import atomos.multiprocessing.atomic

Contribution

Contributions are welcome, please ensure PEP8 is followed and that new code is well-tested prior to making a pull request.

More Repositories

1

flask-login

Flask user session management.
Python
3,569
star
2

axum-login

🪪 User identification, authentication, and authorization for Axum.
Rust
550
star
3

flask-bcrypt

Flask-Bcrypt is a Flask extension that provides bcrypt hashing utilities for your application.
Python
324
star
4

tower-sessions

🥠 Sessions as a `tower` and `axum` middleware.
Rust
214
star
5

flask-uploads

File uploads for Flask.
Python
208
star
6

flask-seasurf

SeaSurf is a Flask extension for preventing cross-site request forgery (CSRF).
Python
190
star
7

logmon

Realtime log reader in Flask
Python
176
star
8

flake

Decentralized, k-ordered unique IDs in Clojure
Clojure
142
star
9

warc-parquet

🗄️ A simple CLI for converting WARC to Parquet.
Rust
103
star
10

axum-sessions

🥠 Cookie-based sessions for Axum via async-session.
Rust
74
star
11

aquamarine

A demo of zero-downtime deploys with Docker Compose and Traefik
Shell
53
star
12

irctk

A simple framework for writing IRC applications
Python
44
star
13

quanta

Distributed CRDT of sparse integer vectors.
Clojure
33
star
14

forma

🐚 An opinionated SQL formatter.
Rust
27
star
15

axum-messages

🛎️ One-time notification messages for Axum.
Rust
26
star
16

tower-sessions-stores

🚃 Previously bundled session stores for `tower-sessions`.
Rust
23
star
17

hyperlight

A performance-focused HTTP reverse proxy
Clojure
19
star
18

flask-themes

Flask Themes
Python
19
star
19

cryptotrade

A simple Python API wrapper for Bitcoin trading platforms such as MtGox and TradeHill
Python
14
star
20

flog

A blog written with Flask
Python
9
star
21

flask-wepay

A Flask wrapper for WePay's Python API
Python
8
star
22

blizzard

HTTP unique ID generation service
Clojure
8
star
23

st

Fast and simple statistics on the command line.
Rust
6
star
24

markov-domains

Finds available domains using Markov chains.
Clojure
6
star
25

nautilus

User authentication and management service
Clojure
5
star
26

yelp-api

A wrapper for Yelp's public API
PHP
4
star
27

affinis

An IRC library for Clojure.
Clojure
4
star
28

wtforms

Python
4
star
29

rauth

A Python library for OAuth 1.0/a, 2.0, and Ofly
Python
4
star
30

simpleirc

An IRC connection layer written in Python.
Python
4
star
31

headers-accept

🤝 The missing `Accept` implementation for `headers::Header`.
Rust
4
star
32

pyxine-branch

Branch of the Python extension for xine
Python
3
star
33

fluyt

ClojureScript HTTP requests
Clojure
3
star
34

cozy

A modern Node API template for the weary traveller
JavaScript
3
star
35

dotfiles

Development environment configuration files.
Shell
3
star
36

ewt

EDN Web Tokens
Clojure
3
star
37

flask-simpleoauth

A dead simple OAuth 1.0a provider in Flask
Python
3
star
38

simpleoauth

Simple, correct OAuth 1.0 and 2.0 signing methods.
Python
2
star
39

kaa

Kaa is the resident IRC bot on VoxInfinitus, written with IrcTK
Python
2
star
40

voxinfinitus

Basic Django apps providing CMS and blog functionality for Voxi
Python
2
star
41

mage

A Clojure-like Lisp.
Python
2
star
42

tasker

simple task manager
Python
2
star
43

ChatOnMacWebAPI-Swift

Swift
2
star
44

chatter

Chatter is a quick and dirty realtime chat application written in Flask
Python
2
star
45

bitpit-https-bridge

A simple Flask app to bridge the unsecured service with a secured page
Python
1
star
46

conceptis.org

My personal site and blog
Python
1
star
47

primes

A simple Clojure program for generating a multiplication table of primes
Clojure
1
star
48

konvej

Httpbin in Clojure.
Clojure
1
star
49

atrium

HTTP Authentication Service
1
star
50

clasp

A dead simple routing DSL for Clojure's ring.
Clojure
1
star
51

celeb

Incomplete Flask gallery project, now abandoned
Python
1
star
52

accord

A simple OAuth 1.0/a, 2.0 consumer client for Clojure.
Clojure
1
star
53

locksmithing

Lock-free, concurrent data structure experiments.
Clojure
1
star