Chronaxis用户手册English
本页目录

chronaxis.execution.record_time_indexes

源码基线:8904c2f744951857659abd40aaa3535d57faf53c

1"""只为周期选窗/事件时长保存一份所需驱动时刻,按索引定位。23每条只写一个实际整数时间;偏移只在单次查询中按记录索引计算,不保存改写时间轴。4"""5from fractions import Fraction6from struct import Struct7from tempfile import TemporaryFile8from ..results.errors import ResultClosedError9from ..results.spool import _reserve_owned_ram,_release_owned_ram,_cleanup_owner101112class RecordTimeIndexes:13    """拥有各必要驱动的一份定长时间文件,所有消费者借用。"""1415    def __init__(self,budget,path,drivers):16        """预付有限索引状态。参数: 预算/私有路径/唯一驱动名称。返回: owner。异常: 原构造错。"""17        self._budget,self._path=budget,path18        self._files={}19        self._counts={}20        self._last={}21        self._held_cost=self._fixed_cost=022        self._closed=False23        self._codec=Struct('>q')24        try:25            _reserve_owned_ram(self,65536+len(drivers)*32768,'_fixed_cost')26            self._counts=dict.fromkeys(drivers,0)27            self._last=dict.fromkeys(drivers)28        except BaseException as error:29            _cleanup_owner(self,error,'record_time_indexes_cleanup_owner','必要驱动索引构造')30            raise3132    def observe_group(self,group):33        """每驱动每实际同刻组只写一次。参数: 完整组。返回: None。异常: 顺序/IO/预算错误。"""34        if self._closed:35            raise ResultClosedError('驱动索引已关闭')36        names={sample.name for sample in group.samples}37        for driver in self._counts:38            if driver not in names:39                continue40            if self._last[driver] is not None and group.time_ns<=self._last[driver]:41                raise ValueError('驱动索引时间回退或重复')42            if driver not in self._files:43                self._files[driver]=TemporaryFile(mode='w+b',dir=self._path,prefix='driver-times-')44            self._budget.reserve_spool(8)45            handle=self._files[driver]46            handle.seek(0,2)47            if handle.write(self._codec.pack(group.time_ns))!=8:48                raise OSError('驱动索引短写')49            self._counts[driver]+=150            self._last[driver]=group.time_ns5152    def count(self,driver):53        """读取已写条数。参数: 驱动。返回: int。异常: 未声明驱动。"""54        return self._counts[driver]5556    def last(self,driver):57        """读取已写末时刻。参数: 驱动。返回: int或None。异常: 未声明驱动。"""58        return self._last[driver]5960    def at(self,driver,index):61        """只读取一个时间整数。参数: 驱动/索引。返回: int。异常: 越界/短读。"""62        if self._closed:63            raise ResultClosedError('驱动索引已关闭')64        if not 0<=index<self._counts[driver]:65            raise IndexError('驱动索引越界')66        handle=self._files[driver]67        handle.seek(index*8)68        data=handle.read(8)69        if len(data)!=8:70            raise ValueError('驱动索引短读')71        return self._codec.unpack(data)[0]7273    def lower(self,driver,time_ns):74        """二分首个不早于time_ns的时刻。参数: 驱动/实际时间。返回: 索引。异常: 原读取错。"""75        lo,hi=0,self._counts[driver]76        while lo<hi:77            mid=(lo+hi)//278            if self.at(driver,mid)<time_ns:79                lo=mid+180            else:81                hi=mid82        return lo8384    def position(self,driver,time_ns):85        """单次查询实际时刻位于哪对记录及其比例,不保存转换时间轴。8687        参数: 驱动/实际时间。返回: (Fraction记录位置,是否超出观测)。异常: 空索引或读取错。88        """89        if not self.count(driver):90            raise ValueError('记录位置需要真实驱动')91        count=self.count(driver)92        right=self.lower(driver,time_ns)93        if right==count:94            position=Fraction(count-1)95            outside=time_ns>self.at(driver,count-1)96        elif self.at(driver,right)==time_ns:97            position=Fraction(right)98            outside=False99        elif right==0:100            position=Fraction(0)101            outside=True102        else:103            left_time,right_time=self.at(driver,right-1),self.at(driver,right)104            position=Fraction(right-1)+Fraction(time_ns-left_time,right_time-left_time)105            outside=False106        return position,outside107108    def shift(self,driver,time_ns,offset_ns,step_ns):109        """按所选周期偏移记录位置,返回实际时刻及首尾裁剪标识。110111        参数: 驱动、实际锚点、带符号偏移ns、正周期ns。返回: (实际ns,是否裁剪)。112        非整周期按原实际间隔比例定位,最终纳秒沿既有最近偶数舍入;不补观测之外的记录。113        异常: 空索引/非法周期/实际读取错。114        """115        if step_ns<=0 or not self.count(driver):116            raise ValueError('周期选窗需要正周期及真实驱动记录')117        count=self.count(driver)118        position,outside=self.position(driver,time_ns)119        target=position+Fraction(offset_ns,step_ns)120        if target<0:121            return self.at(driver,0),True122        if target>count-1:123            return self.at(driver,count-1),True124        left=target.numerator//target.denominator125        if target==left:126            return self.at(driver,left),outside127        a,b=self.at(driver,left),self.at(driver,left+1)128        return round(Fraction(a)+(target-left)*(b-a)),outside129130    @property131    def closed(self):132        """返回关闭状态。参数: 无。返回: bool。异常: 无。"""133        return self._closed134135    def close(self):136        """只关闭本次必要文件,失败可重试。参数: 无。返回: None。异常: 原关闭错。"""137        if self._closed:138            return139        for driver in tuple(self._files):140            self._files[driver].close()141            del self._files[driver]142        _release_owned_ram(self,self._fixed_cost,'_fixed_cost')143        self._closed=True144
Chronaxis 用户手册 · 离线阅读