Что такое параллельность?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Параллельность (Concurrency) в программировании
Параллельность — это свойство системы выполнять несколько задач так, чтобы они казались выполняющимися одновременно. Это не то же самое, что параллелизм (parallelism): параллельность логическая, параллелизм физический.
Основное различие: параллельность vs параллелизм
Параллелизм (Parallelism):
- Несколько процессов одновременно выполняются на разных ядрах процессора
- Истинное одновременное выполнение
- На многоядерном компьютере
Параллельность (Concurrency):
- Несколько задач чередуются (переключаются контекст) на одном ядре
- Кажется, что выполняются одновременно, но на самом деле по очереди
- На одноядерном компьютере можно иметь параллельность, но не параллелизм
// Параллелизм (2 ядра):
Ядро 1: [Task A] [Task A] [Task A]
Ядро 2: [Task B] [Task B] [Task B]
↑ выполняются одновременно
// Параллельность (1 ядро):
Ядро 1: [Task A] [Task B] [Task A] [Task B]
↑ чередуются, но один процессор
В Python: три подхода к параллельности
1. Threading — многопоточность
Несколько потоков в одном процессе, но из-за GIL (Global Interpreter Lock) только один выполняется в момент времени. Идеален для I/O-bound задач.
import threading
import requests
def fetch_url(url):
response = requests.get(url)
print(f"Fetched {url}: {response.status_code}")
urls = ["https://api1.com", "https://api2.com", "https://api3.com"]
# Создаём потоки
threads = []
for url in urls:
thread = threading.Thread(target=fetch_url, args=(url,))
threads.append(thread)
thread.start()
# Ждём завершения всех потоков
for thread in threads:
thread.join()
print("All requests completed")
Плюсы:
- Простой синтаксис
- Разделяют память процесса
Минусы:
- GIL не позволяет истинному параллелизму CPU-bound операций
- Race conditions при доступе к общим данным
2. Asyncio — асинхронность
Один поток, но с кооперативным переключением контекста. Лучше всего для I/O операций.
import asyncio
import aiohttp
async def fetch_url(session, url):
async with session.get(url) as response:
return await response.text()
async def main():
urls = ["https://api1.com", "https://api2.com", "https://api3.com"]
async with aiohttp.ClientSession() as session:
# Запускаем все запросы параллельно
tasks = [fetch_url(session, url) for url in urls]
results = await asyncio.gather(*tasks)
return results
results = asyncio.run(main())
print(results)
Плюсы:
- Легче, чем threading, нет overhead на переключение потоков
- Предсказуемое переключение контекста (в
awaitточках) - Лучше масштабируется на десятки тысяч одновременных операций
Минусы:
- Требует async/await синтаксис
- Не подходит для CPU-bound задач
3. Multiprocessing — мультипроцессинг
Несколько отдельных процессов, каждый со своим Python интерпретатором и памятью. Игнорирует GIL, истинный параллелизм.
from multiprocessing import Pool
import hashlib
def compute_hash(data):
"""CPU-bound задача"""
return hashlib.sha256(data.encode()).hexdigest()
if __name__ == "__main__":
data = [f"data_{i}" for i in range(10)]
# Используем 4 процесса
with Pool(4) as pool:
results = pool.map(compute_hash, data)
print(results)
Плюсы:
- Истинный параллелизм на многоядерных ПК
- Работает для CPU-bound операций
- Изолированы друг от друга
Минусы:
- Overhead на создание процессов
- Сложнее обмениваться данными между процессами
- Требует сериализации (pickle) для передачи данных
Сравнение визуально
# Одна задача - 3 URL, каждый 1 сек
# Последовательно (Sequential)
Время: 3 секунды
[URL1] [URL2] [URL3]
# Threading / asyncio (I/O-bound)
Время: 1 сек (все параллельно)
[URL1, URL2, URL3]
# Multiprocessing (CPU-bound)
На 4-ядерном ПК - 1 сек, на 2-ядерном - 2 сек
Когда что использовать
| Случай | Выбор |
|---|---|
| I/O-bound (HTTP, БД, файлы) | asyncio (лучше) или threading |
| CPU-bound (вычисления, обработка) | multiprocessing |
| Простая параллельность без async/await | threading |
| Тысячи одновременных соединений | asyncio |
| Обработка больших данных на нескольких ядрах | multiprocessing |
Итог
Параллельность в Python достигается тремя способами: threading (на одном ядре с GIL), asyncio (асинхронное переключение контекста), multiprocessing (истинный параллелизм через отдельные процессы). Выбор зависит от природы задач: I/O-bound → asyncio, CPU-bound → multiprocessing, смешанное → комбинация подходов.