@mytec: iter2.3 multithreading p1 done

This commit is contained in:
2026-01-31 20:54:14 +02:00
parent 26f8067c94
commit 3b010fed83
10 changed files with 937 additions and 27 deletions

View File

@@ -53,6 +53,9 @@ from app.services.vegetation_service import vegetation_service, VegetationArea
from app.services.weather_service import weather_service
from app.services.indoor_service import indoor_service
from app.services.atmospheric_service import atmospheric_service
from app.services.parallel_coverage_service import (
calculate_coverage_parallel, get_cpu_count
)
class CoveragePoint(BaseModel):
@@ -349,19 +352,47 @@ class CoverageService:
f"pre-computed {len(grid)} elevations")
_clog(f"━━━ PHASE 2 done: {terrain_time:.1f}s ━━━")
# ━━━ PHASE 3: Point calculation (sync, in thread pool) ━━━
_clog(f"━━━ PHASE 3: Calculating {len(grid)} points (threaded) ━━━")
# ━━━ PHASE 3: Point calculation ━━━
dominant_path_service._log_count = 0 # Reset diagnostic counter
t_points = time.time()
loop = asyncio.get_event_loop()
points, timing = await loop.run_in_executor(
None,
self._run_point_loop,
grid, site, settings, buildings, streets,
spatial_idx, water_bodies, vegetation_areas,
site_elevation, point_elevations
)
use_parallel = len(grid) > 100 and get_cpu_count() > 1
num_workers = get_cpu_count()
if use_parallel:
_clog(f"━━━ PHASE 3: Calculating {len(grid)} points "
f"(PARALLEL, {num_workers} workers) ━━━")
try:
loop = asyncio.get_event_loop()
result_dicts, timing = await loop.run_in_executor(
None,
calculate_coverage_parallel,
grid, point_elevations,
site.model_dump(), settings.model_dump(),
self.terrain._tile_cache,
buildings, streets, water_bodies, vegetation_areas,
site_elevation, num_workers, _clog,
)
# Convert dicts back to CoveragePoint objects
points = [CoveragePoint(**d) for d in result_dicts]
except Exception as e:
_clog(f"Parallel failed ({e}), falling back to sequential")
use_parallel = False
if not use_parallel:
_clog(f"━━━ PHASE 3: Calculating {len(grid)} points (sequential) ━━━")
loop = asyncio.get_event_loop()
points, timing = await loop.run_in_executor(
None,
self._run_point_loop,
grid, site, settings, buildings, streets,
spatial_idx, water_bodies, vegetation_areas,
site_elevation, point_elevations
)
points_time = time.time() - t_points
total_time = time.time() - calc_start
@@ -375,13 +406,17 @@ class CoverageService:
_clog(f" Point calc: {points_time:.1f}s "
f"({points_time/max(1,len(grid))*1000:.1f}ms/point)")
_clog(f" TOTAL: {total_time:.1f}s")
_clog(f" Mode: {'parallel (' + str(num_workers) + ' workers)' if use_parallel else 'sequential'}")
_clog(f" Tiles in memory: {len(self.terrain._tile_cache)}")
if any(v > 0.001 for v in timing.values()):
_clog("=== PER-STEP BREAKDOWN ===")
for step, dt in timing.items():
if dt > 0.001:
_clog(f" {step:20s} {dt:.3f}s "
f"({dt/max(1,len(grid))*1000:.2f}ms/point)")
if isinstance(dt, float):
_clog(f" {step:20s} {dt:.3f}s "
f"({dt/max(1,len(grid))*1000:.2f}ms/point)")
else:
_clog(f" {step:20s} {dt}")
return points