Init
This commit is contained in:
commit
c394677d07
59 files changed
+5149
No files matched your search
@@ -0,0 +1,44 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Демо: потоки выполняются конкурентно — sleep не складывается.
|
||||
|
||||
Запуск из корня курса:
|
||||
python lab02_threads/examples/01_threads_sleep_demo.py
|
||||
|
||||
Пять потоков спят по 0.4 c. Сумма времён = 2 c, реальное время ≈ 0.4 c:
|
||||
пока один поток спит, процессор обслуживает другие.
|
||||
"""
|
||||
import threading
|
||||
import time
|
||||
|
||||
N_THREADS = 5
|
||||
SLEEP = 0.4
|
||||
|
||||
|
||||
def worker(idx: int) -> None:
|
||||
name = threading.current_thread().name
|
||||
t0 = time.perf_counter()
|
||||
time.sleep(SLEEP) # «ожидание сети/диска»
|
||||
dt = time.perf_counter() - t0
|
||||
print(f" {name}: {dt:.3f} c")
|
||||
|
||||
|
||||
def main():
|
||||
print(f"Запускаем {N_THREADS} потоков, каждый спит {SLEEP} c")
|
||||
|
||||
threads = [threading.Thread(target=worker, args=(i,), name=f"поток-{i}")
|
||||
for i in range(N_THREADS)]
|
||||
|
||||
t0 = time.perf_counter()
|
||||
for t in threads:
|
||||
t.start() # ВСЕ стартуют первыми...
|
||||
for t in threads:
|
||||
t.join() # ...потом ВСЕ ждём (start и join не перемешивать!)
|
||||
total = time.perf_counter() - t0
|
||||
|
||||
print(f"Суммарно: {total:.3f} c "
|
||||
f"(сумма времён была бы {N_THREADS * SLEEP:.1f} c)")
|
||||
print(f"Ускорение: x{N_THREADS * SLEEP / total:.1f} — так работает I/O-параллелизм")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,52 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Демо: ThreadPoolExecutor, Future и порядок завершения.
|
||||
|
||||
Запуск из корня курса:
|
||||
python lab02_threads/examples/02_executor_future_demo.py
|
||||
|
||||
Показывает:
|
||||
- pool.map: результаты в порядке входа, даже если завершились в другом;
|
||||
- submit + as_completed: обрабатываем по мере готовности.
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
|
||||
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")))
|
||||
|
||||
from common.tasks import io_fetch
|
||||
|
||||
|
||||
def main():
|
||||
# «Сервер» отвечает тем медленнее, чем больше номер запроса
|
||||
delays = [0.30, 0.25, 0.20, 0.15, 0.10]
|
||||
|
||||
print("--- pool.map: результаты в порядке входа ---")
|
||||
t0 = time.perf_counter()
|
||||
with ThreadPoolExecutor(max_workers=5) as pool:
|
||||
results = list(pool.map(io_fetch, range(5), delays))
|
||||
print(f" порядок: {[r[0] for r in results]} (как на входе)")
|
||||
print(f" время: {time.perf_counter() - t0:.3f} c "
|
||||
f"(последовательный был бы {sum(delays):.2f} c)\n")
|
||||
|
||||
print("--- submit + as_completed: по мере готовности ---")
|
||||
t0 = time.perf_counter()
|
||||
with ThreadPoolExecutor(max_workers=5) as pool:
|
||||
futures = {pool.submit(io_fetch, i, d): i for i, d in enumerate(delays)}
|
||||
for fut in as_completed(futures):
|
||||
item = futures[fut]
|
||||
print(f" завершён запрос {item} "
|
||||
f"(через {time.perf_counter() - t0:.3f} c)")
|
||||
print(f" время: {time.perf_counter() - t0:.3f} c\n")
|
||||
|
||||
print("--- Future: .result() блокирует до готовности ---")
|
||||
with ThreadPoolExecutor(max_workers=2) as pool:
|
||||
fut = pool.submit(io_fetch, 42, 0.20)
|
||||
print(f" done() сразу после submit: {fut.done()}")
|
||||
result = fut.result() # ждём
|
||||
print(f" done() после result(): {fut.done()}, результат: {result}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,58 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Демо: предвестник лабы 3 — потоки НЕ ускоряют счёт.
|
||||
|
||||
Запуск из корня курса:
|
||||
python lab02_threads/examples/03_threads_cpu_demo.py
|
||||
|
||||
Та же схема, что с sleep, но вместо sleep — счёт. Время не уменьшается:
|
||||
GIL разрешает исполнять байт-код Python только одному потоку.
|
||||
Подробное исследование — лабораторная 3.
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
|
||||
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")))
|
||||
|
||||
|
||||
def cpu_worker(n: int) -> None:
|
||||
s = 0.0
|
||||
for i in range(n):
|
||||
s += i ** 0.5 # чистый Python-код: держит GIL
|
||||
return s
|
||||
|
||||
|
||||
def run_threads(n_threads: int, n_per_thread: int) -> float:
|
||||
threads = [threading.Thread(target=cpu_worker, args=(n_per_thread,))
|
||||
for _ in range(n_threads)]
|
||||
t0 = time.perf_counter()
|
||||
for t in threads:
|
||||
t.start()
|
||||
for t in threads:
|
||||
t.join()
|
||||
return time.perf_counter() - t0
|
||||
|
||||
|
||||
def main():
|
||||
TOTAL = 3_000_000
|
||||
|
||||
t0 = time.perf_counter()
|
||||
cpu_worker(TOTAL)
|
||||
t_seq = time.perf_counter() - t0
|
||||
print(f"1 поток, {TOTAL:,} итераций: {t_seq:.3f} c")
|
||||
|
||||
t2 = run_threads(2, TOTAL // 2)
|
||||
print(f"2 потока, по {TOTAL // 2:,}: {t2:.3f} c "
|
||||
f"(ускорение x{t_seq / t2:.2f})")
|
||||
|
||||
t4 = run_threads(4, TOTAL // 4)
|
||||
print(f"4 потока, по {TOTAL // 4:,}: {t4:.3f} c "
|
||||
f"(ускорение x{t_seq / t4:.2f})")
|
||||
|
||||
print("\nУскорения нет (даже хуже!) — GIL. Но тот же код с time.sleep")
|
||||
print("ускорился бы почти идеально (демо 01). Разницу изучаем в лабе 3.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in new issue
Block a user