← Назад к вопросам
Можно ли с помощью мультитрендинга создать несколько потоков?
1.0 Junior🔥 211 комментариев
#Python Core#Асинхронность и многопоточность
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Многопоточность в Python: создание потоков
Отвечу сразу: да, с помощью модуля threading можно создавать несколько потоков, но есть важная оговорка — GIL (Global Interpreter Lock) ограничивает их параллелизм.
Основной способ: threading.Thread
import threading
import time
def worker(name: str, delay: float):
"""Функция, которую будет выполнять поток"""
print(f"{name} начал работу")
time.sleep(delay)
print(f"{name} закончил работу")
# Способ 1: Создание потока через Thread класс
thread1 = threading.Thread(target=worker, args=("Поток-1", 2))
thread2 = threading.Thread(target=worker, args=("Поток-2", 1))
# Запуск потоков
thread1.start()
thread2.start()
# Ожидание завершения
thread1.join()
thread2.join()
print("Все потоки завершены")
Создание потоков через подклассирование
class MyThread(threading.Thread):
def __init__(self, name: str, value: int):
super().__init__()
self.name = name
self.value = value
def run(self):
"""Переопределяем run для выполнения потока"""
print(f"{self.name}: вычисляю сумму")
total = sum(range(1, self.value + 1))
print(f"{self.name}: результат = {total}")
t1 = MyThread("T1", 1000)
t2 = MyThread("T2", 5000)
t1.start()
t2.start()
t1.join()
t2.join()
ThreadPoolExecutor: управление пулом потоков
from concurrent.futures import ThreadPoolExecutor
import requests
def fetch_url(url: str) -> tuple[str, int]:
response = requests.get(url, timeout=5)
return url, response.status_code
urls = [
'https://example.com',
'https://google.com',
]
with ThreadPoolExecutor(max_workers=3) as executor:
results = executor.map(fetch_url, urls)
for url, status in results:
print(f"{url}: {status}")
GIL: главное ограничение потоков в Python
GIL (Global Interpreter Lock) — мьютекс, который позволяет только одному потоку выполнять Python код одновременно.
import threading
import time
def cpu_bound_work():
"""CPU-интенсивная работа"""
total = 0
for i in range(100_000_000):
total += i
return total
# Однопоточное выполнение
start = time.time()
cpu_bound_work()
cpu_bound_work()
print(f"Однопоточно: {time.time() - start:.2f}s") # около 10 сек
# Двухпоточное выполнение (медленнее из-за GIL)
start = time.time()
t1 = threading.Thread(target=cpu_bound_work)
t2 = threading.Thread(target=cpu_bound_work)
t1.start()
t2.start()
t1.join()
t2.join()
print(f"Двухпоточно: {time.time() - start:.2f}s") # медленнее!
Когда threading эффективен
I/O-bound операции (потоки НЕ блокируются на GIL):
import threading
import time
from concurrent.futures import ThreadPoolExecutor
def io_operation(name: str):
"""I/O операция (сеть, диск, БД)"""
print(f"{name}: начало I/O")
time.sleep(2) # Имитируем сетевой запрос
print(f"{name}: конец I/O")
# Однопоточно: 6 сек (2 сек на 3 операции)
start = time.time()
io_operation("op1")
io_operation("op2")
io_operation("op3")
print(f"Результат: {time.time() - start:.2f}s") # 6 сек
# С потоками: примерно 2 сек (параллельно!)
start = time.time()
with ThreadPoolExecutor(max_workers=3) as executor:
executor.map(io_operation, ["op1", "op2", "op3"])
print(f"Результат: {time.time() - start:.2f}s") # около 2 сек
Синхронизация потоков
import threading
class Counter:
def __init__(self):
self.value = 0
self.lock = threading.Lock() # Мьютекс
def increment(self):
# Без lock — race condition!
with self.lock: # Атомная операция
self.value += 1
counter = Counter()
threads = [
threading.Thread(target=counter.increment)
for _ in range(100)
]
for t in threads:
t.start()
for t in threads:
t.join()
print(counter.value) # Всегда 100 (без lock был бы меньше)
Многопоточность vs асинхронность
# Threading: система сама переключает между потоками (OS threads, тяжело)
# Asyncio: кооперативное переключение в одном потоке (легче, быстрее)
import asyncio
async def async_io_operation(name: str):
print(f"{name}: начало")
await asyncio.sleep(2) # Неблокирующая операция
print(f"{name}: конец")
# примерно 2 сек вместо 6
import time
start = time.time()
asyncio.run(asyncio.gather(
async_io_operation("op1"),
async_io_operation("op2"),
async_io_operation("op3"),
))
print(f"Результат: {time.time() - start:.2f}s")
Лучшие практики
- Для I/O: threading или asyncio ✅
- Для CPU-bound: multiprocessing необходим ✅
- Правило: если код содержит I/O или ожидание → threading поможет
- Правило: если код = цикл с вычислениями → multiprocessing нужен
Вывод
Да, можно создавать потоки через threading. Это работает отлично для I/O-операций (API запросы, файлы, БД), но для CPU-интенсивной работы нужно использовать multiprocessing, потому что GIL блокирует истинный параллелизм.