Python - Creating a Thread

Hello, aspiring Python programmers! Today, we're going to dive into the exciting world of threads. Don't worry if you've never heard of threads before – we'll start from the very beginning and work our way up. By the end of this tutorial, you'll be creating threads like a pro!

Python - Creating a Thread

What are Threads?

Before we jump into creating threads, let's understand what they are. Imagine you're cooking a complex meal. You don't do everything one after the other – you might have pasta boiling on one burner while you're chopping vegetables on the cutting board. This is similar to how threads work in programming. They allow different parts of your program to run concurrently, making your code more efficient.

Creating Threads with Functions

The simplest way to create a thread in Python is by using a function. Let's start with a basic example:

import threading
import time

def print_numbers():
    for i in range(5):
        print(f"Number {i}")
        time.sleep(1)

# Create a thread
thread = threading.Thread(target=print_numbers)

# Start the thread
thread.start()

print("Main thread continues to run")

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

print("Thread has finished")

Let's break this down:

  1. We import the threading module, which provides the tools we need to work with threads.
  2. We define a simple function print_numbers() that prints numbers from 0 to 4, with a 1-second pause between each print.
  3. We create a thread using threading.Thread(), specifying our function as the target.
  4. We start the thread with thread.start().
  5. The main program continues to run, printing "Main thread continues to run".
  6. We use thread.join() to wait for our thread to finish before moving on.

When you run this, you'll see that "Main thread continues to run" is printed immediately, while the numbers are being printed in the background. This is the power of threading!

Creating Threads by Extending the Thread Class

Another way to create threads is by extending the Thread class. This method is useful when you want to create a reusable thread object. Here's an example:

import threading
import time

class NumberPrinter(threading.Thread):
    def __init__(self, name):
        threading.Thread.__init__(self)
        self.name = name

    def run(self):
        for i in range(5):
            print(f"{self.name}: Number {i}")
            time.sleep(1)

# Create two threads
thread1 = NumberPrinter("Thread 1")
thread2 = NumberPrinter("Thread 2")

# Start the threads
thread1.start()
thread2.start()

print("Main thread continues to run")

# Wait for both threads to finish
thread1.join()
thread2.join()

print("Both threads have finished")

In this example:

  1. We define a NumberPrinter class that extends threading.Thread.
  2. We override the __init__ method to accept a name for our thread.
  3. We override the run method, which is called when the thread starts.
  4. We create two instances of our NumberPrinter class and start them.
  5. Both threads run concurrently, printing their numbers.

This method gives us more control over our threads and allows us to create multiple instances easily.

Creating Threads using start_new_thread() Function

There's a third way to create threads in Python, using the _thread module's start_new_thread() function. However, this method is considered low-level and is not recommended for most use cases. Here's an example for completeness:

import _thread
import time

def print_numbers(thread_name):
    for i in range(5):
        print(f"{thread_name}: Number {i}")
        time.sleep(1)

# Start two new threads
try:
    _thread.start_new_thread(print_numbers, ("Thread 1",))
    _thread.start_new_thread(print_numbers, ("Thread 2",))
except:
    print("Error: unable to start thread")

# Keep the main thread alive
time.sleep(6)
print("Main thread exiting")

This method is less flexible and doesn't provide as much control as the previous methods. It's also harder to wait for threads to complete using this approach.

Comparison of Thread Creation Methods

Here's a quick comparison of the three methods we've discussed:

Method Pros Cons
Using Functions Simple to implement, good for one-off tasks Less reusable, limited control
Extending Thread Class Reusable, more control, object-oriented Slightly more complex to set up
start_new_thread() Low-level control Harder to manage, less flexible, not recommended

Conclusion

Congratulations! You've just taken your first steps into the world of threading in Python. We've covered three different ways to create threads, each with its own advantages and use cases. Remember, threading can make your programs more efficient, but it also introduces complexity. As you continue your Python journey, you'll learn more about when and how to use threads effectively.

Keep practicing, and soon you'll be threading like a seasoned programmer. Happy coding!

Credits: Image by storyset