perf(531-6): D03 [분석] 속도 — 연도 구간 나란히 프로세스 · 계류 거르기 · 결과 차 0

- 연도 구간을 프로세스 min(연도 수, PLAN_ANALYZE_WORKERS 기본 3)로 나란히 · 끝난 구간은 B 기억 비움
- 저장본이 있는 구간만 이 프로세스에서 지문 확인(다시 [분석] 빠른 길 그대로)
- 계류 거르기: 지형 상자 칸마다 닿는 거리 안의 선만 엔진에 줌 — 계류 거리 · 건너기 · 격자 거리 같음
- 실측(3연도 6.5 km 찬 상태): 797.5 s · 1264 MB → 287.7 s · 합 1942 MB · 갈래 넷 좌표 · 잰 값 차 0
- 시험: 나란히 = 차례 결과 같음 · 계류 거르기 거리 · 교차 같음

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-26 05:04:41 +09:00
co-authored by Claude Opus 5.5
parent f1f0638902
commit a72042ec57
3 changed files with 208 additions and 35 deletions
+60 -3
View File
@@ -17,8 +17,7 @@ SEGMENTS = [
]
@pytest.fixture(scope="module")
def hill() -> Terrain:
def _hill() -> Terrain:
x = np.arange(0.0, 1102.0, 2.0)
y = np.arange(0.0, 402.0, 2.0)
xx, yy = np.meshgrid(x, y)
@@ -26,6 +25,16 @@ def hill() -> Terrain:
return Terrain(x, y, z, np.ones(xx.shape, dtype=bool))
def hill_loader(root, selection, models_dir, cache_dir):
"""나란히 셈 프로세스가 이름으로 부르는 지형(모듈 맨 위 함수)."""
return _hill(), []
@pytest.fixture(scope="module")
def hill() -> Terrain:
return _hill()
@pytest.fixture
def run(tmp_path, hill):
_POOLS.clear()
@@ -37,7 +46,7 @@ def run(tmp_path, hill):
def go(criteria=CRITERIA, corridor_m=150.0):
return analyze.analyze_plan(
tmp_path, SEGMENTS, criteria, loader=loader, corridor_m=corridor_m
tmp_path, SEGMENTS, criteria, loader=loader, corridor_m=corridor_m, workers=1
)
go.calls = calls
@@ -91,6 +100,54 @@ def test_same_input_reads_store(run, monkeypatch) -> None:
run(criteria={**CRITERIA, "max_grade": 0.12})
def test_parallel_years_match_sequential(tmp_path) -> None:
"""연도 구간 나란히(프로세스 둘) = 차례로 — 갈래 넷 노선 좌표 · 잰 값 차 0(531-6)."""
_POOLS.clear()
seq = analyze.analyze_plan(
tmp_path / "a", SEGMENTS, CRITERIA, loader=hill_loader, corridor_m=150.0, workers=1
)
_POOLS.clear()
steps = []
par = analyze.analyze_plan(
tmp_path / "b",
SEGMENTS,
CRITERIA,
loader=hill_loader,
corridor_m=150.0,
workers=2,
on_progress=lambda p, m: steps.append(m),
)
assert [r["routes"] for r in par] == [r["routes"] for r in seq]
assert [r["fingerprint"] for r in par] == [r["fingerprint"] for r in seq]
assert "나란히 2" in steps[0] and steps[-1] == "분석 끝"
# 저장본은 제 프로세스에서 지문만 보고 그대로
again = analyze.analyze_plan(
tmp_path / "b", SEGMENTS, CRITERIA, loader=hill_loader, corridor_m=150.0, workers=2
)
assert [r["stored"] for r in again] == [True, True]
_POOLS.clear()
def test_near_streams_keeps_every_nearest_line(hill) -> None:
"""계류 거르기 — 지형 상자 안 점의 계류 거리 · 건너기가 통째와 같고 먼 선은 빠짐(531-6)."""
import shapely
from shapely.geometry import LineString, MultiLineString
rng = np.random.default_rng(7)
streams = []
for _ in range(80): # 지형(1.1 × 0.4 km) 둘레 5 km 에 흩은 계류
start = rng.uniform(-2000.0, 3000.0, 2)
streams.append([tuple(start + step) for step in np.cumsum(rng.normal(0, 60, (6, 2)), 0)])
kept = analyze.near_streams(hill, streams)
assert 0 < len(kept) < len(streams)
points = shapely.points(rng.uniform((0.0, 0.0), (1100.0, 400.0), (4000, 2)))
whole, part = MultiLineString(streams), MultiLineString(kept)
assert np.array_equal(shapely.distance(points, whole), shapely.distance(points, part))
route = LineString([(0.0, 0.0), (1100.0, 400.0)])
assert route.intersection(whole).equals(route.intersection(part))
assert analyze.near_streams(hill, []) == []
def test_corridor_argument_keeps_b_default(hill) -> None:
line = [SEGMENTS[0]["start"], SEGMENTS[0]["end"]]
base = SearchGrid(line, hill, [], stream_offset_m=10.0)