mirror of
https://github.com/NicolasBohn/NexQuant.git
synced 2026-08-04 02:37:44 +00:00
feat: parallel loop running based on asyncio (#932)
* refactor: split workflow into pkg, add WorkflowTracker & wait_retry * feat: add async LoopBase with parallel workers and step semaphores * fix: replace pickle with dill and run blocking tasks via joblib wrapper * feat: add log format settings, dynamic parallelism & pickle-based snapshot * fix: default step semaphore to 1 and avoid subprocess when single worker * merge bowen's changes * merge tim's changes * refactor: extract component task mapping, add conditional logger setup * lint * refactor: add type hints and safer remain_time metric logging in workflow * lint * fix: allow BadRequestError to be pickled via custom copyreg reducer * fix: stop loop when LoopTerminationError is raised in LoopBase * lint * refactor: make log tag context-local using ContextVar for thread safety * feat: add subproc_step flag and helper to decide subprocess execution * fix: use ./cache path and normalize relative volume bind paths * fix: reset loop_idx to 0 on loop restart/resume to ensure correct flow * fix: avoid chmod on cache and input dirs in Env timeout wrapper * fix: skip chmod on 'cache' and 'input' dirs using find -prune * fix: restrict chmod to immediate mount dirs excluding cache/input * fix: chmod cache and input dirs alongside their contents after entry run * fix: guard chmod with directory checks for cache and input * fix: prefix mount_path in chmod command for cache/input dirs * fix: drop quotes from find exclude patterns to ensure chmod executes * fix: skip chmod on cache/input directories to avoid warning spam * feat: support string volume mappings and poll subprocess stdout/stderr * support remove symbolic link * test: use dynamic home path and code volume in LocalEnv local_simple * fix: skip trace and progress update when loop step is withdrawn * refactor: add clean_workspace util and non-destructive workspace backup * fix: preserve symlinks when backing up workspace with copytree * fix: prevent AttributeError when _pbar not yet initialized in LoopBase * perf: replace shutil.copytree with rsync for faster workspace backup * fix: cast log directory Path to str in tar command of data science loop * fix: use portable 'cp -r -P' instead of rsync for workspace backup * fix: add retry and logging to workspace backup for robustness * refactor: extract backup_folder helper and reuse in DataScienceRDLoop * fix: propagate backup errors & default _pbar getattr to avoid error * fix the division by zero bug * refactor: execute RD loops via asyncio.run and add necessary imports * lint * lint * lint --------- Co-authored-by: Xu <v-xuminrui@microsoft.com>
This commit is contained in:
@@ -78,5 +78,24 @@ class RDAgentSettings(ExtendedBaseSettings):
|
||||
|
||||
initial_fator_library_size: int = 20
|
||||
|
||||
# parallel loop
|
||||
step_semaphore: int | dict[str, int] = 1
|
||||
"""the semaphore for each step; you can specify a overall semaphore
|
||||
or a step-wise semaphore like {"coding": 3, "running": 2}"""
|
||||
|
||||
def get_max_parallel(self) -> int:
|
||||
"""Based on the setting of semaphore, return the maximum number of parallel loops"""
|
||||
if isinstance(self.step_semaphore, int):
|
||||
return self.step_semaphore
|
||||
else:
|
||||
return max(self.step_semaphore.values())
|
||||
|
||||
# NOTE: for debug
|
||||
# the following function only serves as debugging and is necessary in main logic.
|
||||
subproc_step: bool = False
|
||||
|
||||
def is_force_subproc(self) -> bool:
|
||||
return self.subproc_step or self.get_max_parallel() > 1
|
||||
|
||||
|
||||
RD_AGENT_SETTINGS = RDAgentSettings()
|
||||
|
||||
@@ -2,14 +2,19 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Generic, List, Tuple, TypeVar
|
||||
from typing import TYPE_CHECKING, Generic, List, Tuple, TypeVar
|
||||
|
||||
from rdagent.core.conf import RD_AGENT_SETTINGS
|
||||
from rdagent.core.evaluation import Feedback
|
||||
from rdagent.core.experiment import ASpecificExp, Experiment
|
||||
from rdagent.core.knowledge_base import KnowledgeBase
|
||||
from rdagent.core.scenario import Scenario
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from rdagent.utils.workflow.loop import LoopBase
|
||||
|
||||
|
||||
class Hypothesis:
|
||||
"""
|
||||
@@ -248,6 +253,17 @@ class ExpGen(ABC):
|
||||
)
|
||||
"""
|
||||
|
||||
async def async_gen(self, trace: Trace, loop: LoopBase) -> Experiment:
|
||||
"""
|
||||
generate the experiment and decide whether to stop yield generation and give up control to other routines.
|
||||
"""
|
||||
# we give a default implementation here.
|
||||
# The proposal is set to try best to generate the experiment in max-parallel level.
|
||||
while True:
|
||||
if loop.get_unfinished_loop_cnt(loop.loop_idx) < RD_AGENT_SETTINGS.get_max_parallel():
|
||||
return self.gen(trace)
|
||||
await asyncio.sleep(1)
|
||||
|
||||
|
||||
class HypothesisGen(ABC):
|
||||
|
||||
|
||||
Reference in New Issue
Block a user