Что такое поток (Thread) в Python?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Потоки (Threads) в Python
Поток (thread) — это облегчённый процесс выполнения внутри одного процесса Python. Несколько потоков в одном процессе могут работать «параллельно» и делить одно адресное пространство памяти.
Создание потока
Для работы с потоками используется модуль threading:
import threading
def worker(name, delay):
import time
print(f"Поток {name} начал работу")
time.sleep(delay)
print(f"Поток {name} завершился")
# Создание потока
thread = threading.Thread(target=worker, args=("T1", 2))
# Запуск потока
thread.start()
# Ожидание завершения потока
thread.join()
print("Все потоки завершены")
GIL (Global Interpreter Lock) — ключевое ограничение
Самое важное: В CPython (стандартная реализация Python) существует GIL — глобальная блокировка интерпретатора. GIL предотвращает выполнение Python кода несколькими потоками одновременно.
import threading
import time
def cpu_intensive():
total = 0
for i in range(100_000_000):
total += i
return total
# Один поток
start = time.time()
cpu_intensive()
print(f"Один поток: {time.time() - start:.2f} сек")
# Два потока
start = time.time()
t1 = threading.Thread(target=cpu_intensive)
t2 = threading.Thread(target=cpu_intensive)
t1.start()
t2.start()
t1.join()
t2.join()
print(f"Два потока: {time.time() - start:.2f} сек") # Почти не быстрее!
ГIL означает, что многопоточность в Python неэффективна для CPU-bound задач (интенсивные вычисления). Потоки фактически выполняются по очереди, а не параллельно.
Когда потоки полезны: I/O-bound задачи
Потоки хорошо подходят для задач, требующих ожидания (I/O operations):
import threading
import requests
import time
def fetch_url(url):
print(f"Загружаю {url}...")
response = requests.get(url, timeout=5)
print(f"Статус {url}: {response.status_code}")
urls = [
"https://example.com",
"https://google.com",
"https://github.com"
]
# С потоками (быстро)
start = time.time()
threads = [threading.Thread(target=fetch_url, args=(url,)) for url in urls]
for t in threads:
t.start()
for t in threads:
t.join()
print(f"С потоками: {time.time() - start:.2f} сек")
Пока один поток ждёт ответ от сервера, другой может работать. GIL отпускается во время I/O операций.
Синхронизация между потоками
Lock (мьютекс) — для защиты общих ресурсов:
import threading
counter = 0
lock = threading.Lock()
def increment():
global counter
for _ in range(100_000):
with lock: # Защита критической секции
counter += 1
t1 = threading.Thread(target=increment)
t2 = threading.Thread(target=increment)
t1.start()
t2.start()
t1.join()
t2.join()
print(f"Counter: {counter}") # 200000 (без lock было бы меньше)
Event — для синхронизации:
event = threading.Event()
def waiter():
print("Жду события...")
event.wait() # Блокируется до set()
print("Событие произошло!")
def signaler():
import time
time.sleep(2)
event.set() # Сигнализирует остальным
t1 = threading.Thread(target=waiter)
t2 = threading.Thread(target=signaler)
t1.start()
t2.start()
t1.join()
t2.join()
Альтернативы потокам
Для CPU-bound: используй multiprocessing (отдельные процессы, без GIL):
from multiprocessing import Process
def cpu_task():
return sum(range(100_000_000))
p1 = Process(target=cpu_task)
p2 = Process(target=cpu_task)
p1.start()
p2.start()
p1.join()
p2.join()
Для I/O-bound: используй asyncio (async/await, коутины):
import asyncio
import aiohttp
async def fetch(url):
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
return await response.text()
async def main():
await asyncio.gather(
fetch("https://example.com"),
fetch("https://google.com")
)
asyncio.run(main())
Выводы
- Потоки — для I/O-bound задач (сеть, файлы)
- GIL ограничивает параллелизм CPU-bound операций
- Multiprocessing — для CPU-bound (но тяжелее потоков)
- Asyncio — современный способ для асинхронного кода