Atomic Counters in Python
Our primary mechanism for managing state in Python is through communication over queues. However, there are a few other options for managing state. Here we’ll look at using the threading
module and the multiprocessing
module for atomic counters accessed by multiple threads.
In this Python version, we’re using the multiprocessing
module instead of goroutines. The Value
object from multiprocessing
is used as a shared memory location that can be safely accessed by multiple processes.
We create a Value
object to represent our counter. This object is thread-safe and process-safe, so it can be safely incremented by multiple processes.
We then create 50 separate processes, each of which will increment the counter 1000 times. We use a separate function increment
for this, which takes the counter and the number of increments as arguments.
After starting all processes, we wait for them to finish using the join
method.
Finally, we print the final value of the counter.
To run the program:
We expect to get exactly 50,000 operations. If we had used a regular Python integer and incremented it with ops += 1
, we’d likely get a different number, changing between runs, because the processes would interfere with each other. The Value
object ensures that the increments are atomic.
Next, we’ll look at locks, another tool for managing state in concurrent programs.