Init
This commit is contained in:
commit
c394677d07
59 files changed
+5149
No files matched your search
@@ -0,0 +1,38 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Демо: привет, MPI — ранги, размер мира, точка-точка.
|
||||
|
||||
Запуск из корня курса:
|
||||
mpiexec -n 4 python lab08_mpi/examples/01_hello_mpi.py
|
||||
|
||||
Каждый ранг — отдельный процесс с копией программы. Ранги обмениваются
|
||||
сообщениями: ранг 0 рассылает своё имя всем, каждый отвечает.
|
||||
Без mpiexec (обычный python) программа работает как единственный ранг.
|
||||
"""
|
||||
from mpi4py import MPI
|
||||
|
||||
comm = MPI.COMM_WORLD
|
||||
rank = comm.Get_rank()
|
||||
size = comm.Get_size()
|
||||
|
||||
print(f"[до обмена] ранг {rank} из {size}, узел {MPI.Get_processor_name()}")
|
||||
|
||||
if rank == 0:
|
||||
# ранг 0 рассылает задание всем остальным (bcast: всем одно и то же)
|
||||
greeting = f"привет от координатора (ранг 0), всего рангов {size}"
|
||||
else:
|
||||
greeting = None
|
||||
|
||||
greeting = comm.bcast(greeting, root=0) # коллективная: вызывают ВСЕ
|
||||
print(f"ранг {rank}: получил «{greeting}»")
|
||||
|
||||
# точка-точка: каждый ранг (кроме 0) отправляет 0 свой номер
|
||||
if rank != 0:
|
||||
comm.send(rank, dest=0, tag=11)
|
||||
print(f"ранг {rank}: отправил свой номер координатору")
|
||||
else:
|
||||
received = [comm.recv(source=r, tag=11) for r in range(1, size)]
|
||||
print(f"ранг 0: получил номера от рангов {received}")
|
||||
|
||||
if size == 1:
|
||||
print("\nВы запустили без mpiexec — работает один ранг.")
|
||||
print("Попробуйте: mpiexec -n 4 python lab08_mpi/examples/01_hello_mpi.py")
|
||||
@@ -0,0 +1,44 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Демо: ping-pong и замер стоимости обмена между рангами.
|
||||
|
||||
Запуск из корня курса:
|
||||
mpiexec -n 2 python lab08_mpi/examples/02_pingpong_mpi.py
|
||||
|
||||
Ранги перекидывают список чисел туда-обратно. Так измеряют латентность и
|
||||
пропускную способность канала между узлами.
|
||||
"""
|
||||
import time
|
||||
|
||||
from mpi4py import MPI
|
||||
|
||||
comm = MPI.COMM_WORLD
|
||||
rank = comm.Get_rank()
|
||||
size = comm.Get_size()
|
||||
|
||||
if size < 2:
|
||||
print("Нужны минимум 2 ранга: mpiexec -n 2 python lab08_mpi/examples/02_pingpong_mpi.py")
|
||||
raise SystemExit(0)
|
||||
|
||||
ROUNDS = 20
|
||||
for n_bytes in (1_000, 100_000, 1_000_000):
|
||||
data = list(range(n_bytes // 8)) # ~n_bytes байт целых чисел
|
||||
comm.barrier() # синхронный старт замера
|
||||
t0 = time.perf_counter()
|
||||
if rank == 0:
|
||||
for _ in range(ROUNDS):
|
||||
comm.send(data, dest=1, tag=0)
|
||||
comm.recv(source=1, tag=0)
|
||||
elif rank == 1:
|
||||
for _ in range(ROUNDS):
|
||||
comm.recv(source=0, tag=0)
|
||||
comm.send(data, dest=0, tag=0)
|
||||
dt = time.perf_counter() - t0
|
||||
|
||||
if rank == 0:
|
||||
per_round = dt / ROUNDS
|
||||
print(f"{n_bytes:>9,} байт: {ROUNDS} раундов за {dt:.3f} c "
|
||||
f"=> {per_round * 1000:.2f} мс/раунд (туда-обратно)".replace(",", " "))
|
||||
|
||||
if rank == 0:
|
||||
print("\nНа одной машине это IPC (быстро), между узлами — сеть.")
|
||||
print("Эта цена обмена и есть накладные расходы распределённых вычислений.")
|
||||
@@ -0,0 +1,44 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Демо: коллективные операции scatter / gather / reduce / bcast.
|
||||
|
||||
Запуск из корня курса:
|
||||
mpiexec -n 4 python lab08_mpi/examples/03_collectives_mpi.py
|
||||
|
||||
Показывает все четыре коллективные операции на маленьком примере.
|
||||
"""
|
||||
from mpi4py import MPI
|
||||
|
||||
comm = MPI.COMM_WORLD
|
||||
rank = comm.Get_rank()
|
||||
size = comm.Get_size()
|
||||
|
||||
# --- bcast: один -> всем ------------------------------------------------
|
||||
config = {"task": "summa_kvadratov", "n": 100} if rank == 0 else None
|
||||
config = comm.bcast(config, root=0)
|
||||
print(f"ранг {rank}: config = {config}")
|
||||
|
||||
# --- scatter: СПИСОК КУСКОВ (ровно size штук), ранг i получает i-й --------
|
||||
if rank == 0:
|
||||
# каждый кусок — свой список; scatter ждёт список из size кусков!
|
||||
numbers = [[i * 10 + j for j in range(10)] for i in range(size)]
|
||||
else:
|
||||
numbers = None
|
||||
my_chunk = comm.scatter(numbers, root=0) # ранг i получает свой кусок
|
||||
print(f"ранг {rank}: мой кусок {my_chunk[0]}..{my_chunk[-1]} ({len(my_chunk)} шт.)")
|
||||
|
||||
# --- каждый ранг считает СВОЮ часть --------------------------------------
|
||||
my_sum = sum(x * x for x in my_chunk)
|
||||
print(f"ранг {rank}: сумма квадратов моего куска = {my_sum}")
|
||||
|
||||
# --- gather: все части -> список на ранге 0 ------------------------------
|
||||
partial_sums = comm.gather(my_sum, root=0)
|
||||
if rank == 0:
|
||||
print(f"ранг 0: частичные суммы = {partial_sums}")
|
||||
print(f"ранг 0: итого через sum(gather) = {sum(partial_sums)}")
|
||||
|
||||
# --- reduce: то же самое, но сразу со свёрткой (проще и быстрее) ----------
|
||||
total = comm.reduce(my_sum, op=MPI.SUM, root=0)
|
||||
if rank == 0:
|
||||
print(f"ранг 0: итого через reduce(MPI.SUM) = {total}")
|
||||
print("\ngather+sum и reduce(SUM) дали одно и то же — reduce короче.")
|
||||
print("В задании mpi_pi вы используете reduce для суммы попаданий.")
|
||||
@@ -0,0 +1,47 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Демо: π методом Монте-Карло в MPI (reduce).
|
||||
|
||||
Запуск из корня курса:
|
||||
mpiexec -n 4 python lab08_mpi/examples/04_pi_reduce_mpi.py
|
||||
|
||||
Каждый ранг бросает свою порцию «точек» со СВОИМ зерном (rank-зависимым),
|
||||
reduce(SUM) сворачивает попадания. Число рангов не меняет формулу —
|
||||
меняется только распределение бросков.
|
||||
"""
|
||||
import random
|
||||
import time
|
||||
|
||||
from mpi4py import MPI
|
||||
|
||||
comm = MPI.COMM_WORLD
|
||||
rank = comm.Get_rank()
|
||||
size = comm.Get_size()
|
||||
|
||||
N_PER_RANK = 500_000
|
||||
|
||||
|
||||
def count_inside(n: int, seed: int) -> int:
|
||||
rng = random.Random(seed) # зерно зависит от ранга
|
||||
inside = 0
|
||||
for _ in range(n):
|
||||
x = rng.random()
|
||||
y = rng.random()
|
||||
if x * x + y * y <= 1.0:
|
||||
inside += 1
|
||||
return inside
|
||||
|
||||
|
||||
t0 = time.perf_counter()
|
||||
my_inside = count_inside(N_PER_RANK, seed=1000 + rank)
|
||||
total_inside = comm.reduce(my_inside, op=MPI.SUM, root=0)
|
||||
dt = time.perf_counter() - t0
|
||||
|
||||
if rank == 0:
|
||||
total = N_PER_RANK * size
|
||||
pi = 4.0 * total_inside / total
|
||||
print(f"рангов: {size}, бросков на ранг: {N_PER_RANK:,} (всего {total:,})")
|
||||
print(f"π ≈ {pi:.6f} (погрешность {abs(pi - 3.141592653589793):.6f})")
|
||||
print(f"время: {dt:.2f} c")
|
||||
if size == 1:
|
||||
print("\nПопробуйте: mpiexec -n 4 python lab08_mpi/examples/04_pi_reduce_mpi.py")
|
||||
print("Каждый ранг добавляет 500k бросков: точность растёт, время — нет.")
|
||||
Reference in new issue
Block a user