Last Updated on September 12, 2022
You can sleep a thread by calling the time.sleep() function.
In this tutorial you will discover how to sleep a thread in Python.
Let’s get started.
Need to Sleep in a Thread
A thread is a thread of execution in a computer program.
Every Python program has at least one thread of execution called the main thread. Both processes and threads are created and managed by the underlying operating system.
Sometimes we may need to create additional threads in our program in order to execute code concurrently.
Python provides the ability to create and manage new threads via the threading module and the threading.Thread class.
You can learn more about Python threads in the guide:
In concurrent programming we may want the current thread to block or sleep for a specified time.
How can we make threads sleep in Python?
Run loops using all CPUs, download your FREE book to learn how.
What is Sleep
The time.sleep() function will cause the calling thread to block for the specified number of seconds.
Suspend execution of the calling thread for the given number of seconds.
— time — Time access and conversions
For example:
1 2 3 |
... # sleep for 5 seconds time.sleep(5) |
The time.sleep() function takes a floating point number of seconds to sleep.
If a fraction less than zero is provided, then this indicates the number of milliseconds for the calling thread to block.
The argument may be a floating point number to indicate a more precise sleep time.
— time — Time access and conversions
Recall that there are 1,000 milliseconds in one second. Therefore a sleep value of 0.1 will allow the calling thread to sleep for 1/10th of a second or 100 milliseconds.
1 2 3 |
... # sleep for 100 milliseconds time.sleep(0.1) |
We may call the time.sleep() function from the main thread, which is the default thread in your progress. We may also call the time.sleep() function from a new thread used to execute a custom function.
The calling thread may block for less than the time specified, if the process is interrupted.
The actual suspension time may be less than that requested because any caught signal will terminate the sleep() following execution of that signal’s catching routine.
— time — Time access and conversions
This may happen if the user presses Ctrl-C to send a SIGINT (signal interrupt) to the process that owns the thread, which by default will terminate the process.
The calling thread will block for at least the specified number of seconds, but may block for longer.
… the suspension time may be longer than requested by an arbitrary amount because of the scheduling of other activity in the system.
— time — Time access and conversions
This is because the underlying operating system decides what threads should run and when to run them. It may decide to let the thread block for a little longer before waking it up and allowing it to resume execution (e.g. a fraction of a second longer).
The time.sleep() function calls a system function to block the calling thread. e.g. the sleep system call. This function call itself may have more or less precision than you require. For example, although you specify a sleep of one or a few milliseconds, the underlying system call may have a precision limited at tens of milliseconds.
This is a capability provided by the underlying operating system and may be implemented differently on different operating systems, such as Windows, Linux and MacOS.
Next, let’s consider why we might sleep a thread.
Why Use Sleep
There are many reasons why we may want a thread to sleep.
For example:
- Add a delay.
- Slow down execution of a loop.
- Allow other threads to run.
- Force race conditions during debugging.
Let’s take a closer look at each in turn.
Sleep to Introduce a Delay
We may want to introduce a delay into our program.
This may be to avoid overwhelming an external resource, such as:
- Making too many connections to a web server
- creating too many files too quickly.
- Sending many emails too fast.
For example, too many rapid sequential operations on an external resource may trigger computer security measures to protect the resource from a denial of service attack.
It may be to simply slow down a process to permit the user or another thread to take notice and respond to changes within the application.
Sleep to Slow-Down a Loop
We may introduce a sleep to slow down the execution of a loop.
This may be to make the program more usable, such as to allow the user to see and read messages printed each iteration.
It may also be to avoid overwhelming an external resource that is used each iteration of the loop.
Sleep to Let Other Threads Run
Calling sleep will block the current thread.
This will signal to the underlying operating system that the thread is a candidate for a context switch.
You may recall that modern operating systems like Windows, MacOS and Linux achieve multitasking via context switching threads. This is where running threads are suspended and suspended threads are resumed. This process of context switching between threads is occurring continuously by the operating system to simulate the running of multiple programs and program threads concurrently.
Calling sleep is one way to allow other threads in the Python application or other threads on the system to run.
This may be achieved with a call to time.sleep() with zero seconds, for example:
1 2 3 |
... # allow other threads to run time.sleep(0) |
Sleep for Debugging
Adding sleeps to a program can help expose bugs.
Race conditions can occur if two threads attempt to read or modify unprotected variables concurrently or to coordinate with wait/notify.
Often, race conditions are not exposed until some unexpected delay is introduced into a program, such as a resource taking an unusually long time.
We can stress test our concurrent applications and help expose race conditions by adding sleeps to the code while testing.
For example, if one thread is waiting to be notified on a threading.Condition by another thread, and the oher thread calls notify() before the waiting thread calls wait() then this indicates a race condition and the waiting thread will never be notified.
We may be able to force this race condition by adding a call to time.sleep() prior to the waiting thread calling wait() to simulate a natural context-switching delay and see if the wait-notify mechanism used in the program still operates correctly.
You can learn more about this type of race condition in this tutorial:
Next, let’s take a closer look at how to sleep.
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
How to Sleep in a Thread
We can sleep a thread by calling the time.sleep() function from the thread.
For example:
1 2 3 |
... # sleep the current thread for 10 seconds time.sleep(10) |
The sleep function takes a floating point value for the number of seconds to sleep, where fractions of a second are milliseconds.
For example:
1 2 3 |
... # sleep the current thread for 10 milliseconds time.sleep(0.010) |
We can sleep for longer intervals such as minutes and days by specifying these intervals in terms of the number of seconds.
Let’s make this clear with a few examples.
Note: You may recall that although we specify a number of seconds to sleep, that the program may sleep for longer as resuming the thread is at the whim and capabilities of the underlying operating system.
How to Sleep for Milliseconds
There are 1,000 milliseconds in one second.
We can specify a time interval as a floating point fraction of a second in order to sleep for milliseconds.
For example:
- 1,000 milliseconds is 1 second.
- 100 milliseconds is 0.1 seconds.
- 10 milliseconds is 0.01 seconds.
- 1 millisecond is 0.001 seconds.
The example below demonstrates how to sleep for half a second or 500 milliseconds.
1 2 3 4 5 6 7 |
# SuperFastPython.com # example of sleeping for milliseconds from time import sleep # report a message print('Sleeping for half a second') # block sleep(0.5) |
We can update the program to run once every 500 milliseconds or twice per second by calling sleep in a loop.
For example:
1 2 3 4 5 6 7 8 9 10 11 |
# SuperFastPython.com # example of running twice per minute from time import sleep # run forever while True: # do a task # ... # report a message print('Sleeping for half a second') # block sleep(0.5) |
How to Sleep for Seconds
The time.sleep() function takes a number of seconds to sleep as an argument directly.
For example, we may sleep for 30 seconds by providing the value of 30 to the function.
1 2 3 4 5 6 7 |
# SuperFastPython.com # example of sleeping for seconds from time import sleep # report a message print('Sleeping for 30 seconds') # block sleep(30) |
We can update the program to run once every 30 seconds or twice per minute by calling sleep in a loop.
For example:
1 2 3 4 5 6 7 8 9 10 11 |
# SuperFastPython.com # example of running twice per minute from time import sleep # run forever while True: # do a task # ... # report a message print('Sleeping for 30 seconds') # block sleep(30) |
How to Sleep for Minutes
We can sleep for a given number of minutes by specifying the interval in terms of seconds.
For example:
- 1 minute is 60 seconds.
- 10 minutes is 600 seconds.
- 100 minutes is 6,000 seconds.
It may be easier to specify the interval as a multiplication, e.g. 2 minutes and 30 seconds could be specified as 2.5 * (60), which is 150 seconds.
The example below demonstrates how to sleep for 5 minutes specified as a multiplication.
1 2 3 4 5 6 7 |
# SuperFastPython.com # example of sleeping for minutes from time import sleep # report a message print('Sleeping for 5 minutes') # block sleep(5 * 60) |
We can update the program to run once every 5 minutes or 12 times per hour by calling sleep in a loop.
For example:
1 2 3 4 5 6 7 8 9 10 11 |
# SuperFastPython.com # example of running twelve times per hour from time import sleep # run forever while True: # do a task # ... # report a message print('Sleeping for 5 minutes') # block sleep(5 * 60) |
How to Sleep for Hours
We may want to sleep for hours.
This may be helpful to perform an action in the application every hour or twice per day.
This can be achieved by specifying the number of hours to sleep in terms of seconds.
For example:
- 1 hour is 3,600 seconds
- 10 hours is 36,000 seconds
- 100 hours is 360,000 seconds
The sleep interval may be easier to specify in your program as a multiplication. For example, 2 hours and 30 minutes can be specified as 2.5 * (60 * 60), brackets added for clarity.
For example:
- 1 hour: 1 * (60*60)
- 10 hours: 10 * (60*60)
- 100 hours: 100 * (60*60)
The example below demonstrates how to sleep for 12 hours.
1 2 3 4 5 6 7 |
# SuperFastPython.com # example of sleeping for hours from time import sleep # report a message print('Sleeping for 12 hours') # block sleep(12 * (60*60)) |
We can update the program to run once every 12 hours or twice per day by calling sleep in a loop.
For example:
1 2 3 4 5 6 7 8 9 10 11 |
# SuperFastPython.com # example of running twice per day from time import sleep # run forever while True: # do a task # ... # report a message print('Sleeping for 12 hours') # block sleep(12 * (60*60)) |
How to Sleep for Days
We may need our thread to sleep for days.
This may be helpful to perform an action once per day or once per week.
This can be achieved by specifying the number of days to sleep in terms of seconds.
For example:
- 1 day is 86,400 seconds
- 10 days is 864,000 seconds
- 100 days is 8,640,000 seconds
The interval may be easier to specify in your program as a multiplication. For example, 2 days and 12 hours can be specified as 2.5 * (60 * 60 * 24), brackets added for clarity.
- 1 hour: 1 * (60*60*24)
- 10 hours: 10 * (60*60*24)
- 100 hours: 100 * (60*60*24)
The example below demonstrates how to sleep for 7 days.
1 2 3 4 5 6 7 |
# SuperFastPython.com # example of sleeping for days from time import sleep # report a message print('Sleeping for 7 days') # block sleep(7 * (60*60*24)) |
We can update the program to run once a week by calling sleep in a loop.
For example:
1 2 3 4 5 6 7 8 9 10 11 |
# SuperFastPython.com # example of running once per week from time import sleep # run forever while True: # do a task # ... # report a message print('Sleeping for 7 days') # block sleep(7 * (60*60*24)) |
Next, let’s consider some tips when using sleep in your program.
Overwhelmed by the python concurrency APIs?
Find relief, download my FREE Python Concurrency Mind Maps
Tips When Using Sleep
This section provides some times when using the time.sleep() function in your program.
They are:
- Sleep will not release acquired locks.
- Use sleep in a busy-wait loop.
- You can sleep for zero seconds.
- Consider waiting instead of sleeping.
- Protect against SIGINT.
Let’s take a closer look at each in turn.
Sleep Will Not Release Locks
In concurrent programming we can access critical sections of code by first acquiring a lock, such as a mutual exclusion (mutex) lock.
We may also acquire a condition which will acquire its internal lock, or acquire a semaphore which will modify an internal counter protected by a lock.
If we call time.sleep() while holding a lock, it will not release the resource.
For example:
1 2 3 4 5 6 7 |
... # acquire a mutex with lock: # do something ... # sleep for a while sleep(60) |
Sleeping while holding the lock will prevent any other thread from acquiring the lock. The problem with this is that it may result in extended delays within your program.
You should avoid this, unless it is a specific requirement of your program.
Ideally, you would release any locks before putting a thread to sleep.
For example:
1 2 3 4 5 6 7 |
... # acquire a mutex with lock: # do something ... # sleep for a while sleep(60) |
Use a Sleep When Busy-Waiting
Busy waiting, also called spinning, refers to a thread that repeatedly checks a condition in a loop.
It is a form of waiting that invokes continual checking of the desired state, rather than blocking and allowing other threads to run.
We may use busy waiting when trying to coordinate two threads based on timing, to avoid missing an event or change in state.
You can learn more about busy waits in this tutorial:
A spinlock is a specific type of busy waiting used to wait for a mutual exclusion lock.
You can learn more about Spinlocks in this tutorial:
For example, the following loop demonstrates a spinlock where the busy wait loop tries to acquire a mutex lock each iteration.
1 2 3 4 5 6 7 8 9 |
... # example of a busy wait loop for a spinlock while True: # try and get the lock acquired = lock.acquire(blocking=False) # check if we got the lock if acquired: # stop waiting break |
The computational burden of a busy wait loop can be lessened by adding sleep.
This will delay the checking of the desired state each iteration of the loop, but will force the thread to block and allow other threads to run, perhaps improving overall performance.
The example below demonstrates adding a delay with a call to time.sleep() to a spinlock.
For example:
1 2 3 4 5 6 7 8 9 10 11 12 |
... # example of a busy wait loop for a spinlock with a sleep while True: # try and get the lock acquired = lock.acquire(blocking=False) # check if we got the lock if acquired: # stop waiting break else: # sleep for a moment sleep(0.1) |
Sleep for Zero Seconds
You can add a call to time.sleep() for zero seconds.
For example:
1 2 3 |
... # sleep for zero seconds time.sleep(0) |
At first glance, this may look like a “no operation” (noop), e.g. useless and that the compiler may optimize the call out of existence.
Instead, this is a useful trick in concurrent programming.
Specifically, it can be used in computationally intensive threads or threads that are performing CPU intensive work in a loop.
Adding a sleep for zero seconds will signal to the operating system that the thread may be context switched to another thread. The operating system may choose whether or not to honor this switch.
Nevertheless, it may allow a computationally intensive thread a momentary break and allow other threads in the application to progress, perhaps improving overall performance.
Consider Wait Instead of Sleep
We often add a call to time.sleep() to add a delay to the application.
Instead, we may want to block by waiting instead.
This can be achieved by using a concurrency primitive such as a threading.Condition and calling the wait() function with or without a timeout in seconds. The calling thread will block, just like calling a sleep(), but the difference is another thread may call the notify() function on the condition in order to wake up the blocking thread.
For example, we can wait on a condition with a timeout:
1 2 3 4 5 |
... # acquire the condition with condition: # block for 10 seconds or until notified condition.wait(timeout=10) |
We may wait on many concurrency primitives, such as:
- Mutual exclusion locks and reentrant locks via the acquire() function.
- Events via wait().
- Conditions via wait().
- Barriers via wait().
- Semaphores via acquire().
You can learn more about blocking calls and waiting in this tutorial:
Importantly, when calling the wait() function such as a condition, the lock on the primitive is released until the thread is resumed. This is helpful if other threads must acquire the lock in order for the program to progress.
Protect Against Terminal Signals
A call to time.sleep() may be interrupted by a signal.
For example, the user may press Control-C in order to send the SIGINT interrupt signal to the application. This may cause the sleeping thread to raise an exception and in turn terminate the process.
You may want to protect your call to sleep from being interrupted.
This can be achieved by registering a signal handler and taking appropriate action, such as closing the application cleanly once the sleep operation has completed.
This involves first defining a function to be called when the signal is received. The function takes the signal number and the current stack frame.
1 2 3 |
# handle sigint def custom_handler(signum, frame): print('Got a SIGINT, ignoring for now...') |
The handler can then be registered via the signal.signal() function that first specifies the signal to respond to, such as signal.SIGINT (interrupted with Control-C) and the function to call.
For example:
1 2 3 |
... # register the signal handler for control-c signal(SIGINT, custom_handler) |
The example below demonstrates this, handling Control-C signals if they occur while sleeping and preventing the program from terminating.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# SuperFastPython.com # example of protecting a sleep from signal interruption from time import sleep from signal import signal from signal import SIGINT # handle sigint def custom_handler(signum, frame): print('Got a SIGINT, ignoring for now...') # register the signal handler for control-c signal(SIGINT, custom_handler) # report a message print('Sleeping for a moment') # block sleep(5) print('All done') |
Running the program will sleep for five seconds and report a message.
For example:
Sleeping for a moment
All done
If you press Control-C while the program is running, e.g. while sleeping, then the program will handle the SIGINT signal, report a message, and will continue waiting until the sleep is complete.
For example:
1 2 3 4 |
Sleeping for a moment ^C Got a SIGINT, ignoring for now... All done |
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 sleep a thread.
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?