Python: Daemon vs Non-Daemon Threads

Imagine your program is a busy workshop. It has little helpers — threads — that take care of different jobs. Some helpers are serious: they stay until every task is done. Others are more easygoing — they vanish quietly when the main shift ends. These are daemon threads.

In Python, daemon threads are like night-shift workers — they quietly leave when the lights go out.

In this guide, we’ll look at:

  • What daemon and non-daemon threads are
  • How to use them
  • How they behave differently

We’ll keep it simple and fun, with short examples to show how it all works.

What Are Daemon and Non-Daemon Threads?

In Python, every thread can be either a daemon or a non-daemon. The difference is all about what happens when the main program ends.

A non-daemon thread is the default type. It sticks around even if the main thread finishes. Python will wait for it to complete before fully shutting down.

A daemon thread, on the other hand, is more like a background ghost. If the main program ends, it vanishes instantly — no waiting, no cleanup.

One-liner: “If the main program finishes, daemon threads don’t hang around.”

This makes daemon threads perfect for quiet background work that isn’t essential to the final result.

Creating Threads (and Setting Daemon Status)

You can decide if a thread should be a daemon before you start it. There are two ways:

Set it directly:

    t.daemon = True

    Or pass it in when creating the thread:

      t = threading.Thread(target=whisper, daemon=True)

      Let’s see a fun example — a thread that keeps whispering, but only as long as the main program is running:

      import threading
      import time
      
      def whisper():
      
          while True:
              print("Shhh... background whispering...")
              time.sleep(1)
      
      # Set as daemon
      t = threading.Thread(target=whisper, daemon=True)
      t.start()
      
      time.sleep(3)
      print("Main thread is done.")

      Note: In most Python environments, this will stop the daemon thread after 3 seconds — right when the main program ends. The whispering fades away!

      Non-Daemon Thread Example

      Non-daemon threads are the default. They finish their job — even if the main program is ready to leave.

      Think of them like a dedicated cleaner who stays after everyone’s gone, making sure everything’s tidy before the building shuts down.

      Here’s an example:

      import threading
      import time
      
      def cleaner():
      
          for i in range(5):
              print(f"Cleaning... {i}")
              time.sleep(1)
      
      t = threading.Thread(target=cleaner)  # Non-daemon by default
      t.start()
      t.join()
      
      print("Cleaner done. Program ends.")

      The main thread runs and prints its message. Even without t.join(), the program would still not end right away — because the cleaner thread is non-daemon. Non-daemon threads keep the program running until they finish, no matter what the main thread does. The t.join() just makes this more intentional: it tells Python, “Wait here until the cleaner finishes.” Only after that does the program print “Program ends” and shut down.

      Mixing Daemon and Non-Daemon Threads

      Sometimes, you’ll have threads that need to finish their job no matter what, and others that are just doing background tasks. This is where mixing daemon and non-daemon threads makes sense.

      Let’s meet our two thread workers:

      • One is a serious worker — focused and reliable (non-daemon).
      • The other just loves to hum tunes in the background (daemon).

      Here’s how it plays out:

      import threading
      import time
      
      def serious_worker():
      
          for i in range(3):
              print(f"Serious work {i}")
              time.sleep(1)
      
      def hummer():
      
          while True:
              print("🎵 Humming in the background 🎵")
              time.sleep(0.5)
      
      t1 = threading.Thread(target=serious_worker)         # Non-daemon by default
      t2 = threading.Thread(target=hummer, daemon=True)    # Daemon thread
      
      t1.start()
      t2.start()
      t1.join()
      
      print("Main thread ends. Daemon hummer stops here.")

      The serious worker (t1) runs three tasks, one per second. The hummer (t2) starts humming in the background and keeps going.

      But once the main thread and all non-daemon threads (like t1) finish, Python will stop any running daemon threads. That means t2 gets cut off — even if it’s still humming away.

      Daemon threads never block the program from exiting. They follow the main thread’s lead — when the main is done, they’re done too, whether ready or not.

      Checking Daemon Status

      You can easily check if a thread is a daemon by looking at its .daemon property. (In older Python versions, there’s also .isDaemon() method — both work the same.)

      Here’s a quick example:

      import threading
      
      t = threading.Thread(target=print, args=("Hi",), daemon=True)
      t.start()
      
      print(f"Is daemon? {t.daemon}")

      This will print True because we set the thread as a daemon.

      Note: .daemon is the modern, preferred way, but .isDaemon() still works if you see it in older code. Both tell you if the thread is set to run as a daemon.

      Daemon Threads in Classes

      You can make daemon threads inside your own classes by setting self.daemon = True in the thread’s initializer. This way, the thread will run in the background and automatically stop when the main program ends.

      Here’s a fun example with a ghost thread:

      import threading
      import time
      
      class GhostThread(threading.Thread):
      
          def __init__(self):
              super().__init__()
              self.daemon = True  # Set thread as daemon
      
          def run(self):
      
              while True:
                  print("👻 Boo... I'm a ghost thread.")
                  time.sleep(1)
      
      g = GhostThread()
      g.start()
      
      time.sleep(3)
      
      print("Main thread leaves... ghost vanishes.")

      The ghost thread will keep printing until the main thread finishes. Then it quietly disappears, just like a real ghost!

      Summary Table (Quick Reference)

      FeatureDaemon ThreadNon-Daemon Thread
      Ends with main✅ Yes❌ No (must finish first)
      Default type❌ No✅ Yes
      Set with.daemon = True(default, or .daemon = False)
      Ideal forBackground tasksImportant, must-complete work

      Conclusion

      Daemon threads are like helpful assistants who quietly leave when the main work is done — they don’t overstay their welcome. Non-daemon threads, on the other hand, are the serious workers that make sure important tasks get finished before the program ends. Try experimenting by writing a small task manager using both types to see how they work together.

      Remember: “Use daemon threads for quiet background magic — but keep a few serious ones for the real job!”