Last Updated on September 12, 2022
You can change how often Python threads may context switch via the sys.setswitchinterval() function.
In this tutorial you will discover how to retrieve and change the switch interval in Python.
Let’s get started.
What is a Context Switch
In a multitasking operating system, a context switch involves suspending the execution of one thread and resuming the execution of another thread.
The underlying operating system (e.g. Linux, MacOS, or Windows) manages which threads run at what time on the underlying CPU core hardware.
Typically, an operating system will be running many processes, each with one or more threads. There may be hundreds or thousands of threads running at a time as part of normal operation.
Not all threads are able to run at the same time. Instead the operating system simulates multitasking by allowing each thread to run for a short amount of time before pausing the execution of the thread and storing its state and switching to another thread.
The process of suspending one thread and reanimating a suspended thread is called a context switch.
Next, let’s take a look at the context switch interval in Python.
Run loops using all CPUs, download your FREE book to learn how.
What is the Python Switch Interval
The switch interval in Python specifies how long the Python interpreter will allow a Python thread to run before it is forced to be made available for a context switch.
Blocking a thread will signal to the operating system that the thread may be a good candidate for a context switch, although it does not require that a context switch may occur.
A Python thread will block when performing IO operations such as calling print(), performing IO with a file or socket, or waiting on a concurrency primitive.
You can learn more about blocking calls here:
Python only allows one thread to execute at a time given the global interpreter lock (GIL). The Python switch interval allows the Python interpreter to context switch those threads that may be executing a large number of non-blocking function calls.
Python 2 provides a facility to change the number of Python virtual machine bytecode operations executed before the Python interpreter blocked a thread and signaled that it may be context switched.
This was provided by the sys.getcheckinterval() and sys.setcheckinterval() functions.
Set the interpreter’s “check interval”. This integer value determines how often the interpreter checks for periodic things such as thread switches and signal handlers. The default is 100, meaning the check is performed every 100 Python virtual instructions.
— sys — System-specific parameters and functions
These functions have since been deprecated and removed.
Python 3 changed the API from the number of bytecode instructions to a time interval in seconds.
This can be checked and configured via the sys.getswitchinterval() and sys.setswitchinterval() functions.
Set the interpreter’s thread switch interval (in seconds). This floating-point value determines the ideal duration of the “timeslices” allocated to concurrently running Python threads.
— sys — System-specific parameters and functions
The default value for the switch interval is 5 milliseconds set as 0.005 seconds.
This can be checked by calling the sys.getswitchinterval() function.
For example:
1 2 3 |
... # get the switch interval value = sys.getswitchinterval() |
It can be changed to a new value in seconds via the sys.setswitchinterval() function.
For example:
1 2 3 |
... # set the switch interval sys.setswitchinterval(1.0) |
Next, let’s consider why we might change the switch interval.
Why Change the Switch Interval
We may want to change the switch interval for our multithreaded program.
There are two main reasons to change the value, they are:
- Allow threads to run longer before a switch to increase performance, e.g. increase the value.
- Allow threads less running time before a switch to expose race conditions, e.g. decrease the value.
Increasing the switch interval may help improve performance of an application by allowing more non-blocking code to be executed before signaling an availability for a switch.
Decreasing the interval may help to expose race conditions related to the concurrent modification of variables or via the coordination between threads.
Let’s take a closer look at these two reasons.
Increase Switch Time
Threads are typically used to handle blocking operations in an application.
A blocking call made within a thread typically signals that the thread can be context switched.
We may perform many operations in a thread that does not block. These operations may run for longer than the switch interval, in which case they may be paused and suspended by the Python interpreter, signaling to the operating system that a context switch can occur for the thread.
We may wish to increase the switch time interval to allow non-blocking function calls executed in threads more time to complete before signaling a possible context switch.
This may allow non-blocking operations to run without interruption, and then allow blocking operations in the thread to be reached, naturally signaling an availability to context switch, perhaps leading to better performance.
A context switch does have some overhead. Switching too often between long-running tasks is referred to as thrashing and may increase the overall running time of both tasks.
Increasing the switch time may decrease thrashing between threads executing long running tasks, which may reduce the overall running time for both tasks.
Decrease Switch Time
A long switch time may mask undesirable behaviors and bugs in the program.
Allowing a thread a longer time to run is likely to allow it to execute larger blocks of code without interruption.
Race conditions often occur when one thread is context switched in the middle of an operation that is not atomic and is not protected by a concurrency primitive like a lock.
We may have race conditions in our code, such as updating variables for data or program state from multiple threads or in the coordination of two threads using timing.
For more about these two types of race conditions, see:
These race conditions may be rarely if ever exposed given the default (or a chosen) switch interval in your program.
Lowering the switch interval for a multithreaded program may expose race conditions that can then be identified and fixed.
This is a common approach used in unit tests for specific aspects of concurrent programs that involve shared state or coordination.
Next, let’s consider why you should probably not change the switch interval.
Free Python Threading Course
Download your FREE threading PDF cheat sheet and get BONUS access to my free 7-day crash course on the threading API.
Discover how to use the Python threading module including how to create and start new threads and how to use a mutex locks and semaphores
Don’t Change the Switch Interval (probably)
Changing the switch interval can make performance worse.
It is not recommended to play with or change the switch interval unless you have a good hypothesis regarding how changing it may improve performance, and you carefully benchmark performance before and after the change.
A misconception is that Python gives control over when threads are context switched.
This is not true.
Instead, Python only provides a signal to the operating system that a context switch can be performed by blocking a running thread. The operating system may or may not perform a context switch.
As such, a common misconception is that increasing the switch interval will allow chunks of non-blocking Python code to be treated as atomic.
This is also not True.
Recall that atomic refers to an operation that is either executed or not executed. Atomic operations cannot be interrupted. We can simulate atomic operations using concurrency primitives like a mutual exclusion (mutex lock).
You can learn more about atomic operations in Python here:
At best, the switch interval is probabilistic, not deterministic.
Although the switch interval may be increased to a point where a block of code could be completed, the operating system may choose to context switch at any time during the execution.
Further, if the switch interval set in Python is honored by the operating system by chance, your thread may expire this interval in the middle of the block of code if some amount of time was spent executing code prior to the block of code.
If you have a critical section, then you should protect it with a concurrency primitive such as a mutual exclusion (mutex) lock. You should not rely on the switch interval in order for the interrupter and the operating system to treat your critical section as an atomic block.
You can learn more about using locks in Python here:
Next, let’s look at an example of getting the switch interval.
Overwhelmed by the python concurrency APIs?
Find relief, download my FREE Python Concurrency Mind Maps
Example of Getting the Switch Interval
The current switch interval can be retrieved via the sys.getswitchinterval() function.
For example:
1 2 3 |
... # get the switch interval value = sys.getswitchinterval() |
The example below demonstrates retrieving the default switch interval value and reporting it.
1 2 3 4 5 6 |
# SuperFastPython.com # example of reporting the context switch interval from sys import getswitchinterval # report the interval interval = getswitchinterval() print(f'Context switch interval: {interval} seconds') |
Running the example retrieves the default switch interval in seconds and reports it.
We can see that the default is 0.005 seconds, which is 5 milliseconds (recall that there are 1000 milliseconds in a second).
1 |
Context switch interval: 0.005 seconds |
Next, let’s look at an example of setting the switch interval.
Example of Changing the Switch Interval
The switch interval can be changed at any time in your program.
This could be for the duration of your program or for a block of code.
The switch interval can be set to a new value in seconds via the sys.setswitchinterval() function.
For example:
1 2 3 |
... set the switch interval sys.setswitchinterval(1.0) |
The example below reports the default switch interval, then sets a new value to one second, then confirms that the new value was set.
1 2 3 4 5 6 7 8 9 10 11 12 |
# SuperFastPython.com # example of changing the context switch interval from sys import getswitchinterval from sys import setswitchinterval # report the interval interval = getswitchinterval() print(f'Context switch interval: {interval} seconds') # decrease the interval setswitchinterval(1.0) # report the new interval interval = getswitchinterval() print(f'Context switch interval: {interval} seconds') |
Running the example first retrieves and reports the default switch interval.
In this case we can see that the default is 0.005 seconds (5 milliseconds).
We then set the interval to 1 second.
The context interval value is then retrieved and reported, confirming that the new value was set.
1 2 |
Context switch interval: 0.005 seconds Context switch interval: 1.0 seconds |
Further Reading
This section provides additional resources that you may find helpful.
Python Threading Books
- Python Threading Jump-Start, Jason Brownlee (my book!)
- Threading API Interview Questions
- Threading Module API Cheat Sheet
I also recommend specific chapters in the following books:
- Python Cookbook, David Beazley and Brian Jones, 2013.
- See: Chapter 12: Concurrency
- Effective Python, Brett Slatkin, 2019.
- See: Chapter 7: Concurrency and Parallelism
- Python in a Nutshell, Alex Martelli, et al., 2017.
- See: Chapter: 14: Threads and Processes
Guides
- Python Threading: The Complete Guide
- Python ThreadPoolExecutor: The Complete Guide
- Python ThreadPool: The Complete Guide
APIs
References
Takeaways
You now know how to change the switch interval 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?