Chronaxis用户手册English
本页目录

chronaxis.results.budget

源码基线:8904c2f744951857659abd40aaa3535d57faf53c

1"""维护共享资源账本、自有RAM交易槽及未返回owner的有限清理协议。23输入为显式正整数限额及申请bytes,输出为检查后的当前/峰值统计。4RAM申请先校验再分配,释放只能抵销已申请金额;spool保留诊断文件,累计不释放。5AnalysisRunner及执行组件共用账本登记数组nbytes、状态和历史存储费用;它不代表全进程RSS上限。6三个资源事务helper只围绕直接预算调用登记实际归属,或委托真实owner.close,7不创建来源、数组或文件。轻量累计器可复用这些协议,无需加载结果编解码和暂存。8"""910# 明确超限异常,首版不降采样、丢结果或偷改窗口。11from .errors import BudgetExceededError121314def _reserve_owned_ram(owner, amount: int, slot: str) -> None:15    """预约一笔RAM并按实际账本登记owner及指定槽位,覆盖成功后取消。1617    参数: owner已初始化_budget/_held_cost/slot;amount为bytes;slot为实际费用字段。18    返回: None。异常: 原预算/取消传播,未实际入账不增加自有费用。19    边界: 仅围绕一次单线程直接预算调用判断,不用子操作后的总额猜测借用费用。20    """21    # 预算回调可能先更新再抛异常,finally必须登记已成功的这一笔申请。22    before = owner._budget.ram_bytes23    try:24        owner._budget.reserve_ram(amount)25    finally:26        if owner._budget.ram_bytes == before + amount:27            owner._held_cost += amount28            setattr(owner, slot, getattr(owner, slot) + amount)293031def _release_owned_ram(owner, amount: int, slot: str) -> None:32    """抵销一笔实际自有RAM,释放前取消保留金额,释放后取消立即清账。3334    参数: owner持有实际_budget/_held_cost/slot;amount为bytes;slot为对应实际费用。35    返回: None。异常: 原预算/取消传播,恢复后不得重复抵销已释放金额。36    """37    # 空槽不调用外部预算回调,也不把未付金额用于抵销其他owner的费用。38    if amount == 0:39        return40    before = owner._budget.ram_bytes41    try:42        owner._budget.release_ram(amount)43    finally:44        if owner._budget.ram_bytes == before - amount:45            owner._held_cost -= amount46            setattr(owner, slot, getattr(owner, slot) - amount)474849def _cleanup_owner(owner, exc: BaseException, attribute: str, label: str) -> None:50    """尝试关闭构造未返回的真实owner,持续失败将恢复句柄附在原异常。5152    参数: owner为实际部分构造对象;exc为原异常;attribute为恢复属性名;label为说明。53    返回: None,不覆盖原异常。异常: 关闭错误记录在原异常notes中,不向外替换它。54    """55    # 至多两次处理瞬时关闭取消;持续故障保留原对象,调用方恢复后显式close。56    for attempt in range(2):57        try:58            owner.close()59            break60        except BaseException as cleanup:61            exc.add_note(f'{label}清理第{attempt + 1}次失败: {type(cleanup).__name__}')62    if not (getattr(owner, '_closed', False) or getattr(owner, 'closed', False)):63        setattr(exc, attribute, owner)64        exc.add_note(f'释放恢复后调用{attribute}.close()')656667class ResourceBudget:68    """保存限额与单线程共享计数;每次申请失败都保持原计数不变。"""6970    def __init__(self, memory_budget_bytes: int = 268435456, spool_quota_bytes: int | None = None):71        """校验并初始化资源计数,不分配数组或创建文件。7273        参数: memory_budget_bytes为RAM估算bytes;spool_quota_bytes为可选累计限额。74        返回: 新账本。异常: ValueError为bool、非正数或非原生int。75        """76        # 配置从计划传入也重新校验,不能把None磁盘配额解释为无限物理磁盘。77        for value in (memory_budget_bytes, spool_quota_bytes):78            if value is not None and (type(value) is not int or value <= 0):79                raise ValueError('资源限额需要正原生int')80        if memory_budget_bytes is None:81            raise ValueError('RAM限额不能省略')82        self.memory_budget_bytes = memory_budget_bytes83        self.spool_quota_bytes = spool_quota_bytes84        self.ram_bytes = self.peak_ram_bytes = self.spool_bytes = 08586    def reserve_ram(self, amount: int) -> None:87        """在分配前保守申请新层RAM,失败不修改账本。8889        参数: amount为非负原生int bytes。返回: None。90        异常: ValueError为金额错误;BudgetExceededError为超限。91        """92        # 使用Python整数避免账本定宽溢出。93        self._amount(amount)94        if self.ram_bytes + amount > self.memory_budget_bytes:95            raise BudgetExceededError(f'新分析层RAM估算超限: {self.ram_bytes}+{amount}>{self.memory_budget_bytes}')96        self.ram_bytes += amount97        self.peak_ram_bytes = max(self.peak_ram_bytes, self.ram_bytes)9899    def release_ram(self, amount: int) -> None:100        """释放已有申请,不能凭负数或重复释放隐藏状态开销。101102        参数: amount为非负原生int bytes。返回: None。103        异常: ValueError为金额错误或超出当前申请。104        """105        self._amount(amount)106        if amount > self.ram_bytes:107            raise ValueError('RAM释放超出当前申请')108        self.ram_bytes -= amount109110    def reserve_spool(self, amount: int) -> None:111        """写入前累计申请磁盘量,失败或部分写入也保守保留申请。112113        参数: amount为非负原生int bytes。返回: None。114        异常: ValueError为金额错误;BudgetExceededError为累计超配额。115        """116        self._amount(amount)117        if self.spool_quota_bytes is not None and self.spool_bytes + amount > self.spool_quota_bytes:118            raise BudgetExceededError('累计磁盘暂存超过spool_quota_bytes')119        self.spool_bytes += amount120121    @staticmethod122    def _amount(amount: int) -> None:123        """检查金额,防止布尔和负数影响预算。124125        参数: amount为申请金额。返回: None。异常: ValueError为非法金额。126        """127        if type(amount) is not int or amount < 0:128            raise ValueError('资源金额需要非负原生int')129130    def snapshot(self) -> dict:131        """返回独立的小型资源快照,不修改计数。132133        参数: 无。返回: 限额、当前/峰值RAM估算和累计spool预留。134        异常: 无;整进程RSS不在此模型内。135        """136        return {'memory_budget_bytes': self.memory_budget_bytes, 'spool_quota_bytes': self.spool_quota_bytes,137                'ram_estimated_bytes': self.ram_bytes, 'peak_ram_estimated_bytes': self.peak_ram_bytes,138                'spool_reserved_bytes': self.spool_bytes, 'whole_process_rss': 'not_measured'}139
Chronaxis 用户手册 · 离线阅读