Python: Getting Active Threads

Active threads are the threads that are currently running or still alive in your Python program. Knowing which threads are active can help you monitor your program’s progress, manage resources better, or debug issues when multiple threads are involved. In this article, you will learn how to use Python’s threading.enumerate() to get a list of all active threads and threading.active_count() to find out how many threads are currently running. We will explore these functions with simple and fun examples that make it easy to understand and use them in your code.

What Are Active Threads?

Active threads include the main thread plus any other threads that have started but haven’t finished running yet. These are the threads currently alive in your program, doing work or waiting to run. Using functions like threading.enumerate() and threading.active_count() lets you check which threads are still active at any moment. This is especially useful when you want to track your program’s progress, log thread activity, or manage multiple threads more easily.

Using threading.enumerate()

The threading.enumerate() function returns a list of all the Thread objects that are currently alive. This includes the main thread and any other threads that have been started but not yet finished. You can use this to see what threads are running at any moment.

Here’s a simple example where we start a thread that sleeps for a short time, then print the names of all active threads. Adding a delay helps us see the active threads while the worker is still running.

import threading
import time

def worker():
    time.sleep(2)  # Simulate work with a delay

thread = threading.Thread(target=worker, name="Worker-1")
thread.start()

for t in threading.enumerate():
    print(f"Active thread: {t.name}")

In this example, the Worker-1 thread is still alive during the enumerate() call, so you’ll see it listed along with the main thread.

Here’s the same example, but this time we wait for the worker thread to finish using join(). After the thread completes, it’s no longer active and won’t show up in the list from threading.enumerate().

import threading
import time

def worker():
    time.sleep(2)  # Simulate work with a delay

thread = threading.Thread(target=worker, name="Worker-1")
thread.start()

thread.join()  # Wait for the thread to finish

# Now list active threads after worker is done
for t in threading.enumerate():
    print(f"Active thread: {t.name}")

Because the thread has finished when enumerate() is called, only the main thread will be listed as active. This shows how enumerate() reflects the current live threads at the moment you call it.

Using threading.active_count()

The threading.active_count() function returns the number of threads currently alive in your program. This count includes the main thread and any other threads that have started but not yet finished.

Let’s look at a simple example where we start a few threads that do some work by sleeping for a short time. Then, we print the number of active threads right after starting them. This helps you see how many threads are running at that moment.

import threading
import time

def wait():
    time.sleep(2)  # Simulate work by sleeping for 2 seconds

# Start 3 threads that run the wait function
for i in range(3):
    threading.Thread(target=wait, name=f"Thread-{i}").start()

# Print the number of active threads immediately after starting them
print(f"Active threads: {threading.active_count()}")

In this example, you’ll see that active_count() reports at least 4 threads active: the main thread plus the three worker threads. This function is useful for tracking how many threads are currently alive at any point during your program’s execution.

Practical Example: Monitoring Active Threads

Here’s a fun and practical way to see threads in action. In this example, we start five threads, each one sleeping for a short time before printing a message. While they are running, the main thread keeps checking how many are still active and prints out their names. This gives a live look at the threads as they start, run, and finish.

import threading
import time

def task():
    time.sleep(1)
    print(f"{threading.current_thread().name} done")


# Start 5 threads
for i in range(5):
    threading.Thread(target=task, name=f"Task-{i}").start()


# Keep printing active threads while any are still running
while threading.active_count() > 1:  # The main thread is always active

    print(f"Currently active threads ({threading.active_count()}):")

    for t in threading.enumerate():
        print(f"- {t.name}")
    time.sleep(0.5)


print("All threads completed.")

This kind of live thread tracking can be helpful for understanding how threads behave and for debugging more complex threaded programs. You’ll see the thread list shrink as each one finishes.

Notes on Main Thread and Daemon Threads

The main thread is the original thread that runs your program. It stays active until your script finishes or all non-daemon threads complete. Daemon threads, on the other hand, are background threads that do not block the program from exiting — they’re useful for tasks that should not prevent the program from closing, like cleanup work or background monitoring.

Daemon threads still show up in threading.enumerate() and are counted by threading.active_count() while they are alive. You can check whether a thread is a daemon using the .daemon property.

Here’s a simple example that creates both a regular thread and a daemon thread:

import threading
import time

def worker():
    time.sleep(2)
    print(f"{threading.current_thread().name} finished")

# Create a non-daemon thread
normal_thread = threading.Thread(target=worker, name="RegularWorker")
# Create a daemon thread
daemon_thread = threading.Thread(target=worker, name="BackgroundWorker", daemon=True)

normal_thread.start()
daemon_thread.start()

print("Main thread checking active threads:")
for t in threading.enumerate():
    print(f"- {t.name} (Daemon: {t.daemon})")

normal_thread.join()
print("Main thread finished waiting.")

In this code, both threads are started, and you can clearly see which one is a daemon. The main thread waits for the non-daemon thread (RegularWorker) but will not wait for the daemon thread (BackgroundWorker) unless you explicitly call join() on it.

Quick Reference Table

FunctionWhat It Does
threading.enumerate()Returns a list of all currently alive threads, including daemon threads
threading.active_count()Returns the total number of alive threads, including the main thread

Conclusion

Knowing how to get active threads in Python makes it easier to watch what your program is doing behind the scenes. With threading.enumerate(), you can see which threads are still running, and with threading.active_count(), you can quickly find out how many are alive at any moment. These tools are simple but powerful for keeping your threads organized. Try starting a few threads yourself, then use these methods to watch them come and go—it’s a fun way to learn how Python handles multitasking.