Last Updated on April 9, 2022
Python does not have volatile variables and reading variable values is atomic.
In this tutorial you will discover best practices for variables shared between threads in Python.
Let’s get started.
Table of Contents
Volatile Variables
Volatile variables in concurrency programming refer to variables whose values must be retrieved from main memory each time they are accessed.
This is the meaning of “volatile” used in modern compiled programming languages such as Java and C#.
In these languages, the virtual machine may maintain cached copies of variable values per thread or stack space.
This can cause a problem in concurrent programming where one thread may check or update a variable value atomicly although without concurrency primitives and receive an outdated cached value.
Defining a new variable as volatile forces the virtual machine to always retrieve the variable value from main memory rather than a possible cached version. This makes it useful for variables that are shared between threads.
Now that we know what volatile variables are, let’s consider them in Python.
Volatile Variables in Python
Python does not have volatile variables.
The reason is because Python does not require volatile variables.
One aspect for this is because Python does not require variables to be defined before being used, as with compiled languages such as Java.
Another aspect is that the Python virtual machine will always access the value of a variable from main memory, e.g. from the heap.
Finally, accessing the value of a variable in Python is atomic. This means that it is thread safe and that the thread cannot be context switched in the middle of accessing the variable’s value.
This means that we can access shared variables between threads and know we are using the current value of the variable rather than a cached version of the variable.
The presence of the global interpreter lock (GIL) in the reference Python interpreter (CPython) also means that only one thread can execute bytecodes at a time. Therefore, when accessing a variable shared between threads, we know that it cannot be updated by another thread simultaneously.
Now that we know about volatile variables in Python, let’s consider recommendations for shared variables in Python.
Recommendations for Shared Variables
Always treat shared variables as a critical section.
Although accessing variables shared between threads is thread safe and the actual variable value is retrieved from main memory, it is good practice to treat shared variables as critical sections.
This means that the data, variables, and state accessed and modified from multiple threads should be protected using concurrency primitives such as events, semaphores, and mutual exclusion locks (mutex).
For example, a boolean flag shared between threads can be achieved with the thread safe threading.Event class.
You can learn more about events here:
A counter shared between threads can be achieved with a threading.Semaphore.
You can learn more about semaphores here:
And general program state can be protected using a threading.Lock.
You can learn more about mutex locks here:
There are a number of reasons that shared variables should be protected, such as:
- The behavior of the reference Python interpreter may change in the future.
- Other programmers who have to read your code and be confused.
- You may introduce more complex race conditions.
Using concurrency best practices, such as protecting shared variables will avoid these issues, future proofing code to interpreter changes and new developers, and avoid whole classes of concurrency failure modes.
Takeaways
You now know about volatile variables in Python.
Do you have any questions?
Ask your questions in the comments below and I will do my best to answer.
Photo by Harley-Davidson on Unsplash
Do you have any questions?