diff --git a/.jules/bolt.md b/.jules/bolt.md index 61511e5..2c7d17b 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -1,8 +1,3 @@ -## 2025-05-15 - Regex Alternation Performance -**Learning:** Replacing multiple `re.search()` calls for simple literals with a single `re.compile(r'literal1|literal2|...')` regex was ~50% SLOWER in Python. -**Insight:** Python's `re` module likely uses optimized string search algorithms (like Boyer-Moore) for simple literal patterns, which are faster than the state machine overhead of a large alternation regex. -**Action:** Prefer multiple simple `re.search()` calls over complex alternations when patterns are mostly literals. Only use combined regex when tokenization/parsing requires strictly ordered matching or when patterns share complex prefixes. - -## 2025-05-20 - Pre-compiling Regex in Loops -**Learning:** `re.findall(pattern, string)` recompiles (or retrieves from cache) the pattern on every call. In high-frequency functions called inside loops (like complexity estimation), this overhead adds up. -**Action:** Always pre-compile regexes (`re.compile`) into module-level or class-level constants if they are used repeatedly, especially in tight loops or recursive functions. +## 2024-05-18 - [Optimized Asyncio Event Loop Handling] +**Learning:** `asyncio.as_completed()` yields coroutines. Calling `loop.run_until_complete(coro)` for each yielded coroutine inside a synchronous for-loop is a major anti-pattern. It repeatedly blocks the main thread, stops the event loop, and restarts it for every single task, completely defeating concurrency. +**Action:** Always wrap concurrent task aggregation in a single overarching async function (e.g., `async def run_all()`) where you `await` the individual tasks, and call `loop.run_until_complete(run_all())` exactly once to keep the event loop running smoothly. diff --git a/evolutia/evolutia_engine.py b/evolutia/evolutia_engine.py index 66a58b2..dc9d361 100644 --- a/evolutia/evolutia_engine.py +++ b/evolutia/evolutia_engine.py @@ -530,13 +530,21 @@ def generate_variations_async( asyncio.set_event_loop(loop) valid_variations = [] - for coro in tqdm(asyncio.as_completed(async_tasks), total=len(async_tasks), desc="Generando"): - try: - result = loop.run_until_complete(coro) - if result: - valid_variations.append(result) - except Exception as e: - logger.error(f"Excepción no manejada en async worker: {e}") + + # ⚡ Bolt Optimization: Wrap task aggregation in a single async coroutine + # Previously, loop.run_until_complete() was called inside the for-loop. + # This blocked the event loop on each iteration, causing overhead and defeating concurrency. + # Running the loop once with `run_all()` awaits all tasks concurrently. + async def run_all(): + for coro in tqdm(asyncio.as_completed(async_tasks), total=len(async_tasks), desc="Generando"): + try: + result = await coro + if result: + valid_variations.append(result) + except Exception as e: + logger.error(f"Excepción no manejada en async worker: {e}") + + loop.run_until_complete(run_all()) logger.info(f"Generación async completada. {len(valid_variations)} variaciones exitosas.") return valid_variations