Python - thread examples

From NoskeWiki
Jump to navigation Jump to search

About

NOTE: This page is a daughter page of: Python


Here are some examples of how to use threads in python3.


Simple Python thread example: thread > start > join

Two threads printing numbers... `start` them and `join` to wait for them all to finish.

import threading
import time

def print_even_numbers():
    for i in range(0, 10, 2):
        print(f"E:{i}", end='> ')
        time.sleep(0.2)

def print_odd_numbers():
    for i in range(1, 10, 2):
        print(f"Odd:{i}", end='> ')
        time.sleep(0.5)  # Significantly slower.

# Create threads:
even_thread = threading.Thread(target=print_even_numbers)
odd_thread = threading.Thread(target=print_odd_numbers)
# Start threads:
even_thread.start()
odd_thread.start()
# Wait for both threads to complete:
even_thread.join()
odd_thread.join()
# Will print out something like:
#  "E:0> Odd:1> E:2> E:4> Odd:3> E:6> E:8> Odd:5> Odd:7> Odd:9>"
# But not necessarily in that exact order
print("Both threads have finished!")


A python thread pool and lock example: ThreadPoolExecutor > submit > lock

This uses a thread pool where all threads increment a single global variable, and use a lock on it to avoid race conditions.

import threading
from concurrent.futures import ThreadPoolExecutor

# Define the shared counter and its lock:
counter = 0
counter_lock = threading.Lock()

increments_per_worker = 1000  # Increments each worker will perform.

def worker():
    global counter
    for _ in range(increments_per_worker):
        with counter_lock:  # Acquire the lock.
            counter += 1    # Safely increment the counter.
        # Release the lock when leaving the 'with' block.


num_workers = 5  # Number of workers in the thread pool.

# Using ThreadPoolExecutor to manage our workers.
with ThreadPoolExecutor(max_workers=num_workers) as executor:
    # Start all workers.
    futures = [executor.submit(worker) for _ in range(num_workers)]
    # Wait for all workers to finish.
    for future in futures:
        future.result()

print(f"Expected counter value: {increments_per_worker * num_workers}")
print(f"Actual counter value: {counter}")

# NOTE: Without the lock (try to take it away) race conditions might
# mean we don't get exactly 5000 as our counter value.


A python array of thread objects (a class inheriting "Thread")

import threading
import random
import time

class BoardGame:
    def __init__(self, board_size=10):
        self.board_size = board_size     # There are (by default) ten squares in the game.
        self.board = [' '] * board_size
        self.treasure_positions = random.sample(range(board_size), 3)
        print(f'Treasure positions {self.treasure_positions}\n')
        for pos in self.treasure_positions:  # Put a 'T' in the random positions.
            self.board[pos] = 'T'

class Player(threading.Thread):
    def __init__(self, name, game):
        super().__init__()
        self.name = name
        self.game = game
        self.position = 0
        self.treasures = 0

    def run(self):
        while self.position < self.game.board_size:
            if self.game.board[self.position] == 'T':
                self.treasures += 1
                print(f'{self.name} picked up a treasure at position {self.position}!')
                time.sleep(random.uniform(0.01, 0.2))  # Extra time penalty to pickup treasure.
                self.game.board[self.position] = ' '

            time.sleep(random.uniform(0.5, 2))  # Randomize speed of progress.
            self.position += 1  # Player moves ahead one spot.

        print(f'{self.name} reached the finish line with {self.treasures} treasures!')

board_game = BoardGame()

players = [Player("Alice", board_game),
           Player("Bob", board_game), 
           Player("Charlie", board_game)]

print('START:')
for player in players:
    player.start()

for player in players:
    player.join()

# Determine the winner
winner = max(players, key=lambda p: p.treasures)
print(f'{winner.name} wins with {winner.treasures} treasures!')

Output might be something like:

Treasure positions [6, 7, 1]

START:
Charlie picked up a treasure at position 1!
Alice picked up a treasure at position 6!
Alice picked up a treasure at position 7!
Bob reached the finish line with 0 treasures!
Charlie reached the finish line with 1 treasures!
Alice reached the finish line with 2 treasures!
Alice wins with 2 treasures!


Links