Chronaxis用户手册English
本页目录

chronaxis.fast.session_worker

源码基线:8904c2f744951857659abd40aaa3535d57faf53c

1"""可复用文件worker:流式求贡献,获得父进程许可后直传或直接写暂存。23控制和数据独立,任一时刻只有一个尚未交付块。worker不累计总量、不创建4子进程;EOF包含最终块数与已成功关闭的文件事实。父进程拥有取消和回收责任。5"""6from hashlib import sha2567import os8from pathlib import Path9import signal10from time import perf_counter1112from .._control_wire import ControlChannel13from .blocks import batches, encode, LIMIT14from ..dbc_loading import load_dbc_file151617def worker_main(control, data, cancel):18    """运行父授权的文件任务。参数: 控制连接、单向数据连接、取消事件。返回: None。19    异常: 原错误通过控制通道报告;断管退出,finally释放读取器。20    """21    if type(control) is not ControlChannel:22        raise TypeError('fast工作进程需要固定字节控制端点')23    signal.signal(signal.SIGINT, signal.SIG_IGN)24    reader = None25    database = None26    identity = None27    try:28        while True:29            command = control.recv()30            if command[0] == 'close':31                break32            if command[0] not in ('file', 'program_file'):33                raise ValueError('未知fast文件命令')34            programs_checked = command[0] == 'program_file'35            _, index, spec, directory, expected_digest = command36            from .stream import FileContributions37            import cantools38            # 复用DBC只限同一冻结内容;变化属于任务失败,不能混合解码口径。39            content = Path(spec['dbc']).read_bytes()40            digest = sha256(content).hexdigest()41            if digest != expected_digest:42                raise ValueError('运行期间DBC内容变化')43            if identity != digest:44                database = load_dbc_file(spec['dbc'], cantools)45                if sha256(Path(spec['dbc']).read_bytes()).hexdigest() != digest:46                    raise ValueError('加载期间DBC内容变化')47                identity = digest48            reader = FileContributions(spec, database, cancel, _programs_checked=programs_checked)49            count = 050            clocks = dict(compute_seconds=0.0, credit_wait_seconds=0.0, send_seconds=0.0, write_seconds=0.0)51            blocks = iter(batches(reader))52            while True:53                if cancel.is_set():54                    raise InterruptedError('fast文件计算取消')55                started = perf_counter()56                try:57                    records = next(blocks)58                except StopIteration:59                    clocks['compute_seconds'] += perf_counter() - started60                    break61                packet = encode(index, count, records)62                records = None63                clocks['compute_seconds'] += perf_counter() - started64                control.send(('offer', index, count, len(packet)))65                started = perf_counter()66                route = control.recv()67                clocks['credit_wait_seconds'] += perf_counter() - started68                if route == ('close',):69                    return70                started = perf_counter()71                if route == ('direct',):72                    data.send_bytes(packet)73                    clocks['send_seconds'] += perf_counter() - started74                    control.send(('delivered', index, count, len(packet)))75                elif route == ('spool',):76                    path = Path(directory) / f'{index}-{count}.block'77                    temporary = path.with_suffix('.part')78                    with temporary.open('xb') as output:79                        if output.write(packet) != len(packet):80                            raise OSError('贡献暂存未完整写入')81                    from ..results.platform_files import move_no_replace82                    move_no_replace(temporary,path)83                    clocks['write_seconds'] += perf_counter() - started84                    control.send(('stored', index, count, len(packet)))85                else:86                    raise ValueError('未知贡献交付许可')87                packet = None88                count += 189                # 等待父确认,直传缓冲不能随主进程处理速度无界累积。90                if control.recv() != ('next',):91                    return92            facts = reader.summary()93            if spec.get('_profile', False):94                clocks.update(reader.timings)95            reader = None96            control.send(('eof', index, count, facts, clocks, os.getpid()))97    except (EOFError, BrokenPipeError):98        pass99    except BaseException as error:100        try:101            control.send(('error', type(error).__name__, str(error)))102        except (EOFError, BrokenPipeError, OSError):103            pass104    finally:105        if reader is not None:106            reader.close()107        control.close()108        data.close()109
Chronaxis 用户手册 · 离线阅读