Init
This commit is contained in:
commit
c394677d07
59 files changed
+5149
No files matched your search
@@ -0,0 +1,41 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Демо: spawn — каждый процесс заново импортирует модуль.
|
||||
|
||||
Запуск из корня курса:
|
||||
python lab04_multiprocessing/examples/01_spawn_demo.py
|
||||
|
||||
Показывает, что на Windows/spawn дочерний процесс заново выполняет
|
||||
модуль верхнего уровня. Поэтому защита __main__ обязательна.
|
||||
Здесь же видно время старта процесса.
|
||||
"""
|
||||
import multiprocessing
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
print(f"[импорт модуля] pid={os.getpid()}, parent={os.getppid()}, "
|
||||
f"метод={multiprocessing.get_start_method()}")
|
||||
|
||||
|
||||
def worker(x):
|
||||
return x * x
|
||||
|
||||
|
||||
def main():
|
||||
print(f"\n[главный процесс] pid={os.getpid()}")
|
||||
ctx = multiprocessing.get_context() # spawn на Windows и macOS
|
||||
|
||||
t0 = time.perf_counter()
|
||||
with ctx.Pool(2) as pool:
|
||||
results = pool.map(worker, range(8))
|
||||
dt = time.perf_counter() - t0
|
||||
|
||||
print(f"pool.map -> {results}")
|
||||
print(f"время (включая старт 2 процессов): {dt * 1000:.1f} мс")
|
||||
print("\nОбратите внимание: строка [импорт модуля] могла напечататься")
|
||||
print("дважды-трижды (для каждого воркера при spawn). На fork — один раз.")
|
||||
print("Вывод: старт воркеров не бесплатный — это накладные расходы лабы 4.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,62 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Демо: что можно, а что нельзя передать в Pool (pickle).
|
||||
|
||||
Запуск из корня курса:
|
||||
python lab04_multiprocessing/examples/02_pickle_demo.py
|
||||
|
||||
Вложенные функции и лямбды не пиккелятся — PicklingError.
|
||||
Модульные функции — можно. Отсюда правило: kernel для Pool живёт
|
||||
на уровне модуля (как dispatch_kernel в common.tasks).
|
||||
"""
|
||||
import multiprocessing
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")))
|
||||
|
||||
from common.tasks import dispatch_kernel, smoke_params
|
||||
|
||||
|
||||
def module_level_double(x): # МОЖНО: функция уровня модуля
|
||||
return x * 2
|
||||
|
||||
|
||||
def make_nested():
|
||||
def nested_double(x): # НЕЛЬЗЯ: вложенная функция
|
||||
return x * 2
|
||||
return nested_double
|
||||
|
||||
|
||||
def main():
|
||||
ctx = multiprocessing.get_context()
|
||||
|
||||
print("--- модульная функция: работает ---")
|
||||
with ctx.Pool(2) as pool:
|
||||
print(f" pool.map(module_level_double, [1,2,3]) = "
|
||||
f"{pool.map(module_level_double, [1, 2, 3])}")
|
||||
|
||||
print("\n--- lambda: PicklingError ---")
|
||||
try:
|
||||
with ctx.Pool(2) as pool:
|
||||
pool.map(lambda x: x * 2, [1, 2, 3])
|
||||
except Exception as e:
|
||||
print(f" {type(e).__name__}: {str(e)[:90]}...")
|
||||
|
||||
print("\n--- kernel задачи через dispatch_kernel: работает ---")
|
||||
task_name = "primes"
|
||||
chunks = None
|
||||
task = __import__("common.tasks", fromlist=["TASKS"]).TASKS[task_name]
|
||||
data = task["build"](smoke_params(task_name))
|
||||
chunks = task["split"](data, 2)
|
||||
payload = [(task_name, ch) for ch in chunks]
|
||||
with ctx.Pool(2) as pool:
|
||||
partials = pool.map(dispatch_kernel, payload)
|
||||
print(f" подсчёт простых ≤ 2000: {task['combine'](partials)} "
|
||||
f"(ожидалось 303)")
|
||||
|
||||
print("\nВывод: всё, что уходит воркерам, должно пиккелиться —")
|
||||
print("поэтому в этом курсе kernel диспетчеризуется по имени задачи.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,66 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Демо: Process + Queue — ручная организация воркеров.
|
||||
|
||||
Запуск из корня курса:
|
||||
python lab04_multiprocessing/examples/03_process_queue_demo.py
|
||||
|
||||
Pool — удобный «конвейер». Process+Queue — ручная схема: воркеры сами берут
|
||||
задачи из очереди. Это основа для producer-consumer в лабе 5.
|
||||
"""
|
||||
import multiprocessing
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")))
|
||||
|
||||
|
||||
def worker(task_q, result_q):
|
||||
"""Воркер: берёт задачи, пока не встретит None — «маркер конца»."""
|
||||
name = multiprocessing.current_process().name
|
||||
while True:
|
||||
task = task_q.get()
|
||||
if task is None:
|
||||
result_q.put((name, "done"))
|
||||
break
|
||||
idx, value = task
|
||||
time.sleep(0.05) # «полезная работа»
|
||||
result_q.put((name, f"задача {idx}: {value}² = {value ** 2}"))
|
||||
|
||||
|
||||
def main():
|
||||
ctx = multiprocessing.get_context()
|
||||
task_q = ctx.Queue()
|
||||
result_q = ctx.Queue()
|
||||
|
||||
n_workers = 3
|
||||
workers = [ctx.Process(target=worker, args=(task_q, result_q),
|
||||
name=f"воркер-{i}")
|
||||
for i in range(n_workers)]
|
||||
for w in workers:
|
||||
w.start()
|
||||
|
||||
# кладём задачи
|
||||
for i in range(9):
|
||||
task_q.put((i, i + 1))
|
||||
# маркеры конца — по одному на воркер
|
||||
for _ in range(n_workers):
|
||||
task_q.put(None)
|
||||
|
||||
# собираем результаты
|
||||
done = 0
|
||||
t0 = time.perf_counter()
|
||||
while done < n_workers:
|
||||
name, msg = result_q.get()
|
||||
if msg == "done":
|
||||
done += 1
|
||||
print(f" [{name}] завершился")
|
||||
else:
|
||||
print(f" [{name}] {msg}")
|
||||
for w in workers:
|
||||
w.join()
|
||||
print(f"время: {time.perf_counter() - t0:.2f} c (9 задач по 0.05 c на 3 воркерах)")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in new issue
Block a user