Привет, Хабр!
В прошлой статье я рассуждал о том, почему Fortran в 2025 году всё ещё жив и даже растет в рейтингах. В комментариях справедливо заметили: «Философия — это хорошо, но как это применить современному разработчику? Зачем мне Fortran, если я пишу на Python?».
Это правильный вопрос. Сегодня я хочу ответить на него кодом, а не словами.
Я покажу, как использовать Fortran в качестве «числодробилки» для Python. Мы возьмем задачу, на которой интерпретатор Python гарантированно просядет, и ускорим её в 150 раз, используя инструмент, который уже есть в вашем numpy.
Речь пойдет не о замене Python, а о симбиозе: удобный интерфейс Python + сырая мощь Fortran.
Почему Python тормозит (и это нормально)
Мы любим Python за динамическую типизацию и удобство. Но за это приходится платить. Когда вы пишете вложенные циклы, интерпретатор на каждой итерации проверяет типы данных, выделяет память под новые объекты и ищет методы сложения/умножения.
Если операций тысячи — это незаметно. Если миллионы — скрипт превращается в слайд-шоу.
Обычно в таких случаях рекомендуют использовать pandas или numpy. Это действительно эффективно — но только если задачу можно выразить через векторные или матричные операции. Как только появляется сложная итеративная зависимость, при которой текущее значение вычисляется на основе результата предыдущего шага, векторизация либо невозможна, либо превращает код в запутанную конструкцию, которую трудно читать и поддерживать.
Здесь на сцену выходят компилируемые языки.
Задача: Фрактал Мандельброта
Почему я выбрал именно генерацию фрактала для демонстрации?
Независимость данных: Каждый пиксель считается отдельно (идеально для параллелизма, но сегодня рассмотрим однопоточный вариант для чистоты эксперимента).
Тяжелая математика: Для каждой точки нужно выполнить цикл проверки (до 100-200 итераций) с комплексными числами.
Масштаб: Картинка 2000x2000 — это 4 миллиона точек. Умножаем на 100 итераций — получаем 400 миллионов операций.
Это идеальный «стресс-тест». Это тот случай, когда Python упирается в свой потолок производительности, и никакие ухищрения не помогут кардинально изменить ситуацию без смены инструмента.
Инструмент: F2PY
Внутри пакета numpyживет утилита F2PY (Fortran to Python). Она позволяет взять файл с кодом на Fortran и одной командой скомпилировать его в модуль, который Python импортирует как родную библиотеку.
Реализация
1. Python (Как не надо делать для High Load)
Вот так выглядит наивная реализация на Python. Она понятна, красива, но мучительно медленна.
import time
import matplotlib.pyplot as plt
def mandelbrot_python(height, width, max_iter):
# Создаем пустую матрицу
output = [[0 for _ in range(width)] for _ in range(height)]
for i in range(height):
# Преобразуем координаты пикселя в координаты на плоскости
y0 = -1.5 + (i * 3.0) / height
for j in range(width):
x0 = -2.0 + (j * 3.0) / width
x, y = 0.0, 0.0
iteration = 0
# Тот самый "тяжелый" цикл
while (x * x + y * y <= 4.0) and (iteration < max_iter):
xtemp = x * x - y * y + x0
y = 2.0 * x * y + y0
x = xtemp
iteration += 1
output[i][j] = iteration
return output
# --- Запуск и визуализация ---
if __name__ == "__main__":
height, width = 2000, 2000
max_iter = 100
print("Начинаем расчёт фрактала на Python...")
start = time.time()
image = mandelbrot_python(height, width, max_iter)
end = time.time()
print(f"Расчёт занял: {end - start:.2f} секунд")
# Отображаем результат
plt.figure(figsize=(10, 6))
plt.imshow(image, cmap='hot', origin='upper')
plt.title("Множество Мандельброта (Python, наивная реализация)")
plt.axis('off')
plt.tight_layout()
plt.show()
На моем ноутбуке расчет кадра 2000x2000 занимает около 30 секунд.
2. Modern Fortran (Ускоритель)
Напишем то же самое на Fortran. Забудьте про стереотипы о перфокартах: современный стандарт языка (Fortran 2008/2018) выглядит чисто.
Создаем файл fractal_mod.f90:
SUBROUTINE compute_mandelbrot(min_x, max_x, min_y, max_y, width, height, max_iter, output)
IMPLICIT NONE
! Строгая типизация. REAL(8) соответствует float64 в Python
REAL(8), INTENT(IN) :: min_x, max_x, min_y, max_y
INTEGER, INTENT(IN) :: width, height, max_iter
INTEGER, INTENT(OUT) :: output(height, width)
! --- Директивы для F2PY ---
! Эти комментарии видит утилита сборки. Мы говорим:
! "Python, создай массив output сам, используя размеры width и height,
! и верни его как результат функции".
!f2py intent(in) min_x, max_x, min_y, max_y, width, height, max_iter
!f2py intent(out) output
!f2py depend(width, height) output
INTEGER :: i, j, iter
REAL(8) :: x0, y0, x, y, xtemp, dx, dy
dx = (max_x - min_x) / (width - 1)
dy = (max_y - min_y) / (height - 1)
DO i = 1, height
y0 = min_y + (i - 1) * dy
DO j = 1, width
x0 = min_x + (j - 1) * dx
x = 0.0d0
y = 0.0d0
iter = 0
! Математика та же, но выполняется на уровне процессора
DO WHILE ((x*x + y*y <= 4.0d0) .AND. (iter < max_iter))
xtemp = x*x - y*y + x0
y = 2.0d0*x*y + y0
x = xtemp
iter = iter + 1
END DO
output(i, j) = iter
END DO
END DO
END SUBROUTINE compute_mandelbrot
3. Сборка
Если у вас установлен компилятор (например, бесплатный gfortran), сборка занимает одну строку в терминале:
python -m numpy.f2py -c fractal_mod.f90 -m fractal_lib
Мы получаем бинарный файл (.pyd или .so), который Python воспринимает как родной модуль.
4. Результат
Теперь напишем небольшой Python-скрипт, который:
· импортирует наш Fortran-модуль,
· запускает расчёт,
· замеряет время,
· по желанию рисует картинку.
import time
import numpy as np
import fractal_lib # модуль, собранный через F2PY
try:
import matplotlib.pyplot as plt
except ImportError:
plt = None
if __name__ == "__main__":
width = 2000
height = 2000
max_iter = 100
start = time.time()
# Вызываем Fortran как обычную функцию из Python
image = fractal_lib.compute_mandelbrot(
-2.0, 1.0, # min_x, max_x
-1.5, 1.5, # min_y, max_y
width,
height,
max_iter,
)
end = time.time()
print(f"Время расчета через Fortran: {end - start:.4f} сек")
print(f"Тип возвращаемого объекта: {type(image)}") # это будет numpy.ndarray
if plt is not None:
plt.figure(figsize=(8, 8))
plt.imshow(image, cmap="magma", extent=(-2.0, 1.0, -1.5, 1.5))
plt.title("Фрактал Мандельброта (Fortran + Python)")
plt.xlabel("Re")
plt.ylabel("Im")
plt.tight_layout()
plt.show()
else:
print("matplotlib не установлен, пропускаю визуализацию.")
Время выполнения: ~0.2 секунды.
Мы получили ускорение в 150 раз. Просто переписав "узкое горлышко" на языке, предназначенном для математики.

Фрактал — это красиво, но где это применить в продакшене? Эта связка (Python + Fortran) работает везде, где есть сложные численные методы:
Финансовое моделирование (Monte Carlo): Когда нужно прогнать миллион сценариев поведения рынка для оценки рисков (VaR). Python управляет данными, Fortran генерирует сценарии.
Обработка сигналов и изображений: Если вам нужно применить нестандартный фильтр к картинке 4K или обработать поток с датчиков вибрации по хитрому алгоритму, стандартные функции OpenCV могут не подойти. Свой цикл на Fortran решит проблему.
Моделирование физики (CFD, Теплопроводность): Инженеры пишут на Fortran решатели (сольверы) дифференциальных уравнений, а на Python делают интерфейс и визуализацию.
Legacy-код: В мире науки (геофизика, климат) существуют терабайты проверенного, отлаженного кода на Fortran. Переписывать его на C++ дорого и опасно (можно внести ошибки). Проще обернуть его через F2PY и использовать в современном стеке.
Вывод
Старое не значит бесполезное. Fortran в 2025 году занял уникальную нишу — это "второй пилот" для Python в задачах High Performance Computing. Он безопаснее C++ (благодаря строгой типизации и отсутствию ручного управления памятью в простых случаях), его синтаксис заточен под математику, а интеграция с Python работает "из коробки".
Если ваш код упирается в процессор, возможно, стоит не оптимизировать Python, а просто делегировать работу профессионалу.
P.S. Тема гибридного программирования (Python + нативные языки) обширная, и в одну статью всё не уместить. Я продолжаю систематизировать свой опыт и методические материалы по этой теме. Если вам интересно следить за обновлениями или задать вопрос — заглядывайте в мой профиль, там есть контакты и ссылки на мои проекты.
Комментарии (5)

Vitvitsky
10.12.2025 06:46
Код из вашего примера(без fortran) за статью спасибо, если когда-нибудь пригодится, попробую что-то написать на fortran

lopppka
10.12.2025 06:46Или ноутбук какой то очень старый, или его совсем замусорили, но на телефоне фрактал генерировался меньше 5 секунд.

black_warlock_iv
10.12.2025 06:46REAL(8)непереносимо и не рекомендуется к употреблению. Если почему-то нет уверенности в дефолтномDOUBLE PRECISION, то лучше использоватьREAL64изISO_FORTRAN_ENV.
MAXH0
Старый добрый Фортран. Один из моих первых языков программирования. Помню, как писал на нем первые лабы.