Ответ
Для оптимизации CPU-bound задач в Python можно использовать:
- Многопроцессорность (модуль
multiprocessing), так как GIL блокирует потоки:
from multiprocessing import Pool
def heavy_computation(x):
return x * x
with Pool(4) as p:
result = p.map(heavy_computation, range(10))
-
Cython - компиляция Python-кода в C для ускорения.
-
Numba - JIT-компилятор для числовых операций:
from numba import jit
@jit(nopython=True)
def fast_func(x):
# ускоренный код
return x * x
-
Использование C-расширений (ctypes, CFFI).
-
Оптимизация алгоритмов - выбор более эффективных алгоритмов (O(n) вместо O(n²)).
-
NumPy - для векторных операций вместо циклов.
Для I/O-bound задач лучше подходят асинхронные подходы (asyncio) или потоки.
Ответ 18+ 🔞
А, ну ты про то, как в Питоне эту ебучую GIL обойти, чтобы железо на полную выжимать? Да, история древняя, как говно мамонта. Сидит этот питонячий глобальный интерпретатор, как манда с ушами, и не даёт потокам нормально работать. Короче, слушай сюда, варианты есть.
Если у тебя задачи CPU-bound, то есть чистая математика, перемножение матриц до посинения, то потоки — это пиздец, они в очередь встанут. Тут надо процессы запускать, у каждого свой GIL будет. Модуль multiprocessing тебе в помощь. Смотри, как просто:
from multiprocessing import Pool
def heavy_computation(x):
return x * x
with Pool(4) as p:
result = p.map(heavy_computation, range(10))
Вот так, блядь, размазал работу по четырём ядрам и поехали. Но только передавать туда-сюда данные между процессами — это отдельная песня, овердохуища накладных расходов может быть.
Второй фокус — это Cython. Берёшь свой питонячий код, немного начиняешь статической типизацией, как колбасу салом, и компилируешь в C. Получается почти нативный код, летает. Но это уже, блядь, почти другой язык учить.
Третий вариант, особенно для числодробилки — Numba. Это просто волшебство, ёпта. Над функцией декоратор повесил, и она в машинный код компилируется прямо при первом запуске.
from numba import jit
@jit(nopython=True)
def fast_func(x):
# ускоренный код
return x * x
Выглядит как Python, а работает — огонь. Но поддерживает не все конструкции, это да.
Ну и классика жанра — писать критические куски на C/C++ и прикручивать через ctypes или CFFI. Это для настоящих мазохистов, которые любят прострелить себе оба колена, но зато потом хвастаться.
А ещё, чувак, самый главный пункт, который все забывают — оптимизация алгоритмов. Можно хоть на ассемблере писать, но если у тебя алгоритм квадратичной сложности на миллионе элементов, то ты просто мудак. Сначала мозги включи, потом уже процессы плоди.
И для операций с массивами — NumPy, конечно. Он всё векторизовано делает на низком уровне, циклы на питоне для этого — чистое самоубийство.
А вот если задачи I/O-bound (сеть, диск, база данных), то тут процессы — это из пушки по воробьям. Тут уже asyncio или хотя бы потоки рулят. GIL на операциях ввода-вывода отпускает, так что можно параллельно много чего ждать.
Короче, выбор инструмента зависит от задачи. Не будь, как Герасим, который всё одним методом — "утопить". Соображай, что ты делаешь.