Использование потоков (threads) в Python для параллельных вычислений требует понимания их ограничений и правильного применения. Из-за Global Interpreter Lock (GIL), только один поток может выполнять Python bytecode в любой момент времени. Это означает, что потоки не обеспечивают истинный параллелизм для CPU-bound задач, где необходимо много вычислительной мощности. Вместо этого, они полезны для I/O-bound задач, где потоки могут ждать ввода-вывода, позволяя другим потокам работать.
Как использовать потоки:
threading
:
import threading
def worker(data):
# Здесь выполняется какая-то работа, например, чтение из файла или сетевой запрос
result = process_data(data) # Замените на вашу логику
print(f"Thread finished processing {data}: {result}")
Thread
:
threads = []
for i in range(5): # Создаем 5 потоков
t = threading.Thread(target=worker, args=(i,)) #Передаем аргумент
threads.append(t)
for t in threads:
t.start()
for t in threads:
t.join() # Блокирует выполнение, пока поток не завершится
print("All threads finished")
Пример I/O-bound задачи:
import threading
import requests
def download_image(url, filename):
try:
response = requests.get(url, stream=True)
response.raise_for_status() # Проверка на ошибки HTTP
with open(filename, 'wb') as out_file:
for chunk in response.iter_content(chunk_size=8192):
out_file.write(chunk)
print(f"Downloaded {filename} from {url}")
except requests.exceptions.RequestException as e:
print(f"Error downloading {url}: {e}")
image_urls = [
"https://www.easygifanimator.net/images/samples/video-to-gif-sample.gif",
"https://upload.wikimedia.org/wikipedia/commons/2/2c/Rotating_earth_%28large%29.gif",
"https://i.imgur.com/rQk7w2q.gif",
]
threads = []
for i, url in enumerate(image_urls):
filename = f"image_{i}.gif"
t = threading.Thread(target=download_image, args=(url, filename))
threads.append(t)
t.start()
for t in threads:
t.join()
print("All images downloaded.")
Эффективность и ограничения:
multiprocessing
, который обходит GIL и позволяет запускать несколько процессов, выполняющихся параллельно на разных ядрах CPU.Использование Lock
для синхронизации:
import threading
counter = 0
lock = threading.Lock()
def increment():
global counter
for _ in range(100000):
with lock:
counter += 1
threads = []
for _ in range(2):
t = threading.Thread(target=increment)
threads.append(t)
t.start()
for t in threads:
t.join()
print(f"Counter value: {counter}") # Должно быть 200000
Ключевые моменты: