Python - thread examples
Jump to navigation
Jump to search
Contents
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!