Daemon Threads in Python – What Are They and How to Create Them?

Python Daemon Thread

Hello everyone! In today’s post, we’ll be looking at using Daemon Threads in Python. Before we start off with the main topic, let us look at what a Daemon Thread is first!


Daemon Threads

A Daemon Thread is a type of thread that can run independently in the background. These kinds of threads execute independently of the main thread. So these are called non-blocking threads.

When might you need Daemon threads in Python?

Suppose you need to have a long running task which tries to read log files. This task must alert the user when it detects an error message in the logs.

We can assign a daemon thread for this task, which can keep monitoring our log files, while our main program does it’s usual work!

The best part about daemon threads is that they will automatically stop the execution once the main program finishes!

In case you need a short task, a daemon thread will stop execution after it returns. However, due to this nature, daemon threads are extensively used for long-running background tasks.

Now, let’s look at an example which shows how we can use them in Python!


Using Daemon Threads in Python – A Hands-On Implementation

These examples in Python will use the threading module in Python, which is part of the standard library.

import threading

To illustrate the power of daemon threads, let’s first create two threads, A and B.

We’ll make thread A perform a short computation, while thread B tries to monitor a shared resource.

If this resource is set to True, we’ll make thread B alert the user about the status.

import threading
import time

# Set the resource to False initially
shared_resource = False 
 # A lock for the shared resource
lock = threading.Lock()

def perform_computation():
    
    # Thread A will call this function and manipulate the resource
    print(f'Thread {threading.currentThread().name} - performing some computation....')
    shared_resource = True
    print(f'Thread {threading.currentThread().name} - set shared_resource to True!')
    print(f'Thread {threading.currentThread().name} - Finished!')
    time.sleep(1)

def monitor_resource():
    # Thread B will monitor the shared resource
    while shared_resource == False:
        time.sleep(1)
    print(f'Thread {threading.currentThread().name} - Detected shared_resource = False')
    time.sleep(1)
    print(f'Thread {threading.currentThread().name} - Finished!')


if __name__ == '__main__':
    a = threading.Thread(target=perform_computation, name='A')
    b = threading.Thread(target=monitor_resource, name='B')

    # Now start both threads
    a.start()
    b.start()

Here, Thread A will set shared_resource to True, and thread B will wait for this resource to be True.

Output

Thread A - performing some computation....
Thread A - set shared_resource to True!
Thread A - Finished!
Thread B - Detected shared_resource = False
Thread B - Finished!

Notice that both threads are normal threads. Now let’s make thread B to be a daemon thread. Let’s see what happens now.

To do this, we can set it as a parameter in the threading.Thread(daemon=True) method.

import threading
import time

shared_resource = False # Set the resource to False initially
lock = threading.Lock() # A lock for the shared resource

def perform_computation():
    # Thread A will call this function and manipulate the resource
    print(f'Thread {threading.currentThread().name} - performing some computation....')
    shared_resource = True
    print(f'Thread {threading.currentThread().name} - set shared_resource to True!')
    print(f'Thread {threading.currentThread().name} - Finished!')
    time.sleep(1)

def monitor_resource():
    # Thread B will monitor the shared resource
    while shared_resource == False:
        time.sleep(1)
    print(f'Daemon Thread {threading.currentThread().name} - Detected shared_resource = False')
    time.sleep(1)
    print(f'Daemon Thread {threading.currentThread().name} - Finished!')


if __name__ == '__main__':
    a = threading.Thread(target=perform_computation, name='A')
    b = threading.Thread(target=monitor_resource, name='B', daemon=True) # Make thread B as a daemon thread

    # Now start both threads
    a.start()
    b.start()

Output

Thread A - performing some computation....
Thread A - set shared_resource to True!
Thread A - Finished!
Daemon Thread B - Detected shared_resource = False

Here, notice that the daemon thread does not finish. This is because it will automatically get killed by the main thread.

The non-blocking nature of daemon threads make it very useful for a lot of Python applications.


Conclusion

In this article, we learned about how we can use Daemon Threads in our Python application


References

  • Python Threading Module Documentation
  • JournalDev article on Daemon Threads in Python