← Назад к вопросам

Что будешь использовать для вычислительной задачи?

2.0 Middle🔥 191 комментариев
#Python Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Выбор инструмента для вычислительных задач

Выбор зависит от типа задачи, требуемой производительности и доступных ресурсов. Вот мой подход к принятию решения.

Первый вопрос: что это за вычисления?

Нужно разобраться в типе задачи:

Вычислительная задача?
├─ Математические операции (Numpy, Cython)
├─ Машинное обучение (PyTorch, TensorFlow)
├─ Обработка данных (Pandas, Polars, Dask)
├─ Граф обработка (NetworkX, DGL)
└─ Универсальные вычисления (multiprocessing, asyncio)

Решение 1: Если это численные вычисления → Numpy

Для математических операций Numpy — золотой стандарт:

import numpy as np
import time

# Неоптимально: Python loop
def python_calculation(n):
    result = 0
    for i in range(n):
        result += i ** 2
    return result

# Оптимально: Numpy (в 100+ раз быстрее)
def numpy_calculation(n):
    arr = np.arange(n)
    return np.sum(arr ** 2)

# Бенчмарк
start = time.time()
python_calculation(10_000_000)
print(f"Python: {time.time() - start:.3f}s")

start = time.time()
numpy_calculation(10_000_000)
print(f"Numpy: {time.time() - start:.3f}s")
# Python: 2.500s
# Numpy: 0.020s

Решение 2: Машинное обучение → PyTorch / TensorFlow

Для ML использую специализированные фреймворки:

import torch
import numpy as np

# Матричные вычисления
matrix_a = torch.randn(1000, 1000)
matrix_b = torch.randn(1000, 1000)

# На GPU (если доступен)
if torch.cuda.is_available():
    matrix_a = matrix_a.cuda()
    matrix_b = matrix_b.cuda()

result = torch.matmul(matrix_a, matrix_b)
print(f"Result shape: {result.shape}")

Преимущества:

  • Оптимизированы для GPU
  • Автоматическое дифференцирование
  • Параллельные вычисления из коробки

Решение 3: Обработка больших данных → Pandas / Dask

Для работы с датафреймами:

import pandas as pd
import dask.dataframe as dd

# Маленькие данные → Pandas
df = pd.read_csv('data.csv')
result = df.groupby('category')['value'].mean()

# Большие данные (не влезает в память) → Dask
ddf = dd.read_csv('large_*.csv')
result = ddf.groupby('category')['value'].mean().compute()

Решение 4: Если нужен максимум производительности → Cython

Для критичных по производительности функций:

# fibonacci_cy.pyx (Cython)
cpdef int fibonacci(int n):
    if n <= 1:
        return n
    return fibonacci(n - 1) + fibonacci(n - 2)

# setup.py
from setuptools import setup
from Cython.Build import cythonize

setup(
    ext_modules=cythonize("fibonacci_cy.pyx")
)

# Использование
from fibonacci_cy import fibonacci
result = fibonacci(35)  # намного быстрее чем Python

Решение 5: Параллельные вычисления → Multiprocessing

Для CPU-bound задач на нескольких ядрах:

from concurrent.futures import ProcessPoolExecutor
import numpy as np

def compute_chunk(chunk):
    # Тяжелые вычисления
    return np.sum(chunk ** 2)

# Данные
data = np.arange(100_000_000).reshape(4, -1)

# Параллельная обработка
with ProcessPoolExecutor(max_workers=4) as executor:
    results = list(executor.map(compute_chunk, data))
    total = sum(results)
    print(f"Total: {total}")

Решение 6: Асинхронность → asyncio (только для I/O!)

ВАЖНО: asyncio НЕ для вычислений, только для I/O:

import asyncio

# ✅ Правильно: I/O-bound операция
async def fetch_data(url):
    # network request
    await asyncio.sleep(1)
    return "data"

async def main():
    results = await asyncio.gather(
        fetch_data("url1"),
        fetch_data("url2"),
        fetch_data("url3")
    )
    print(results)

# ❌ НЕПРАВИЛЬНО: CPU-bound операция
async def cpu_bound():
    return sum(i ** 2 for i in range(100_000_000))
    # asyncio не поможет! Используй multiprocessing

Решение 7: Распределенные вычисления → Spark / Ray

Для огромных объемов данных на кластере:

from pyspark.sql import SparkSession

spark = SparkSession.builder.appName("BigCompute").getOrCreate()
df = spark.read.csv("huge_file.csv")
result = df.groupBy("category").agg({"value": "mean"}).collect()

Или с Ray:

import ray

@ray.remote
def compute(data):
    return sum(i ** 2 for i in data)

ray.init()
results = ray.get([compute.remote(chunk) for chunk in chunks])

Матрица выбора

ЗадачаРекомендацияЗачем
Математика 10K чиселNumpy100x быстрее Python
ML модельPyTorch/TensorFlowGPU поддержка, autodiff
Big Data (GB)PandasУдобный API
Big Data (TB)Dask/SparkПараллельная обработка
Критичная функцияCython10-100x ускорение
Множество задач на CPUmultiprocessingИспользование всех ядер
I/O операцииasyncioКоротор переключения
Кластер обработкаSpark/RayМасштабируемость

Реальный пример: обработка изображений

import numpy as np
from PIL import Image
from concurrent.futures import ProcessPoolExecutor
from pathlib import Path

def process_image(path: str) -> np.ndarray:
    """Обработка одного изображения"""
    img = Image.open(path)
    # Фильтр, трансформация и т.д.
    data = np.array(img)
    # Numpy для быстрых вычислений
    result = np.convolve(data.flatten(), [1, 2, 1], mode='same')
    return result

def process_images(image_dir: str, num_workers: int = 4) -> list:
    """Обработка множества изображений параллельно"""
    paths = list(Path(image_dir).glob("*.jpg"))
    
    with ProcessPoolExecutor(max_workers=num_workers) as executor:
        # multiprocessing для CPU-bound
        results = list(executor.map(process_image, paths))
    
    return results

Мой алгоритм выбора

  1. Профилирование — найди узкие места (cProfile, line_profiler)
  2. Анализ — что именно медленно?
  3. Выбор — используй таблицу выше
  4. Тестирование — оцени прирост производительности
  5. Оптимизация — повтори для других узких мест

Главное правило: не оптимизируй раньше, чем профилируешь.

Что будешь использовать для вычислительной задачи? | PrepBro