정책을 부르는 주기와 결과를 소비하는 주기가 다르다
카메라가 20 ms마다 관측을 만든다고 정책도 매번 20 ms 안에 끝나는 것은 아니다. 생산자는 자료를 넣고 소비자는 꺼내 처리한다. 그 사이 잠시 보관하는 자료 구조가 큐다. FIFO(first in, first out)는 먼저 들어온 자료부터 꺼내는 순서다. 서비스 시간은 한 자료를 처리하는 시간, 대기는 처리를 시작하기 전 머문 시간이다. 완료 나이는 취득부터 결과 준비까지의 경과이며 둘을 포함한다.
관측/추론/명령 발행/저수준 제어의 주기를 따로 기록한다. 정책이 만든 action chunk를 여러 제어 tick에 나눠 소비할 수도 있다. 이때 추론 한 번을 제어 명령 한 번으로 세면 안 된다. M27.03의 적용 시각과 실제 목표 도달도 여전히 별개다. 빠르게 명령을 발행해도 그 근거인 관측이 오래되었을 수 있다.
가상 입력률은 20 ms 간격이면 50개/s이고 단일 작업자의 일정 서비스 시간이 30 ms이면 최대 서비스율은 약 33.3개/s다. 무한 FIFO에 계속 넣고 병렬화/누락·입력 감속이 없다면 차이인 약 16.7개/s만큼 대기열이 장기적으로 늘 수 있다. 유한 큐는 메모리를 제한할 뿐 과잉 입력을 자동 처리하지 않는다. 실제 서비스 시간 변동/휴지 구간도 있어 평균률만 같다는 조건으로 짧은 기한을 보장하지 않는다.
같은 네 관측을 FIFO로 처리한다
관측 ID 0/1/2/3의 취득과 도착은 각각 0/20/40/60 ms로 같다고 가정한다. 센서/전송 지연은 이번 표에서 0이고 하나의 단조 시계다. 단일 비선점 작업자가 즉시 시작해 매번 30 ms 처리한다. 비선점은 이미 시작한 작업을 새 자료가 왔다고 중간에 바꾸지 않는다는 뜻이다. 네 입력 뒤에는 새 입력이 없고, 대기 자료를 모두 처리한다.
그림 M27.04-1. 각 칸은 서로 다른 역할/근거다. 나란히 비교할 항목이며 위아래가 시간 순서를 뜻하지 않는다. 직접 제작한 개념도이며 본문의 조건과 함께 읽는다.
| ID | 도착(ms) | 시작(ms) | 완료(ms) | 대기(ms) | 완료 나이(ms) |
|---|---|---|---|---|---|
| 0 | 0 | 0 | 30 | 0 | 30 |
| 1 | 20 | 30 | 60 | 10 | 40 |
| 2 | 40 | 60 | 90 | 20 | 50 |
| 3 | 60 | 90 | 120 | 30 | 60 |
대기는 시작−도착, 완료 나이는 완료−취득이다. 각 행의 완료 나이=대기+30 ms가 된다. 취득→도착이 0이라는 특수 가정 때문에 이렇게 간단하며 실제 경로에서는 앞단 지연도 더한다. 허용 완료 나이가 45 ms라면 ID 2/3은 초과한다. 누락 없이 처리했다는 것과 필요한 시점에 유효했다는 것은 다른 성질이다.
최신 대기 관측만 남기면 일부 계산을 생략한다
latest-only를 이번 예에서는 '처리 중인 작업은 유지하고, 대기 슬롯 하나는 새 관측으로 교체한다'고 정확히 정의한다. 처리 중인 입력까지 포함한 총 한 개 제한이 아니다. 60 ms처럼 도착/완료가 겹치면 먼저 새 도착으로 대기 슬롯을 갱신한 다음 완료 작업자가 꺼낸다는 사건 순서도 정한다. 다른 동시성 순서에서는 결과가 달라질 수 있다.
ID 0은 0~30 ms, ID 1은 30~60 ms 처리한다. 40 ms의 ID 2는 대기하다가 60 ms의 ID 3으로 교체된다. 따라서 ID 3을 60~90 ms 처리하고 ID 2는 처리하지 않는다. 처리한 ID의 완료 나이는 30/40/30 ms이고 최대는 40 ms다. 네 입력 중 처리 3개/대체 누락 1개라는 분모를 함께 적는다. FIFO의 30/40/50/60 ms와 비교할 수 있지만 이것은 이 사건표의 결과이며 모든 최신 슬롯 구현의 지연 상한은 아니다.
새 관측이 더 오지 않거나 서비스가 길어지면 슬롯 하나여도 완료 관측은 오래될 수 있다. 입력 대체를 했다는 사실만으로 deadline/관측 나이를 보장하지 않는다. 실행 전에 취득 stamp·결과 생성/도착·적용 시각을 연결해 만료를 확인한다. 새 봉투에 오래된 관측에서 나온 행동을 담아도 관측이 새로워지지 않는다. clock 점프/재시작과 중복/역순 ID도 별도 처리한다.
버려도 되는 자료인지는 의미 계약이 정한다
절대 목표는 정한 프레임/기준의 최종 값을 나타내고, 증분 명령은 이전 값/동작에 더하는 변화를 나타낸다. 초기 관절값이 0.3 rad이고 절대 목표 0.4/0.5/0.6 rad 중 두 번째를 생략해도 마지막 목표값 자체는 0.6 rad다. 다만 중간 경로/속도·충돌 전제는 달라질 수 있어 실제 동작이 동등하다는 뜻은 아니다.
반면 +0.1/+0.1/+0.1 rad를 순차 누적하는 계약에서 두 번째를 버리면 최종 값은 0.5 rad이고 모두 적용한 0.6 rad와 다르다. '열기→삽입→닫기' 같은 순서 의존 skill도 최신 하나로 바꿀 수 없다. 시각 추적/시간창 정책은 중간 관측이 필요한 경우가 있어 영상도 무조건 버릴 수 있는 것은 아니다. 명령 schema의 absolute/delta·unit/frame·sequence/기준·실행 시각과 task/정책 버전·누락 처리 규칙을 확인한다.
실시간 관측 소비 경로에서 일부를 버려도 원본 학습/감사 기록을 모두 보존하려면 별도 경로와 저장 용량/오류 처리가 필요하다. '모든 행 기록' 요구를 latest 슬롯으로 구현하면 누락을 숨기게 된다. 원본 기록과 모델이 실제 소비한 ID를 구분하면 어떤 관측에서 행동이 나왔는지 재현할 수 있다.
백프레셔는 압력을 앞단에 전달하는 설계다
백프레셔(backpressure)는 소비자가 감당하지 못할 때 생산 속도를 줄이거나 입력을 막는 식으로 압력을 앞단에 전달하는 방식이다. Python Queue 공식 문서는 유한 maxsize의 put이 공간이 날 때까지 막히거나 지정 방식에 따라 Full을 낼 수 있음을 설명한다. Queue(maxsize=1) 자체가 기존 항목을 최신 것으로 교체하는 기능은 아니다. 경쟁 스레드에서 qsize/empty 값도 다음 연산 성공을 보장하지 않는다.
입력을 막으면 카메라/드라이버 앞단 버퍼에 오래된 프레임이 쌓이거나 취득 누락이 일어날 수 있다. 단순히 애플리케이션 큐만 작게 해서는 전체 경로를 알 수 없다. ROS Jazzy QoS의 history/depth는 미들웨어 보관 정책이며 애플리케이션/장치·추론 큐 전체의 나이 보장은 아니다. reliable도 무한 처리율이나 모든 단계의 영구 저장을 의미하지 않는다.
따라서 자료별로 오래된 입력 버림/새 입력 거부·생산 감속/기록 분리와 만료·누락 알림을 정한다. 속도만 낮출 때도 정책/학습 시간 간격·제어기 계약에 미치는 영향을 검증한다. 기존 5.9 추론과 6.4 감독기를 연결해 과부하를 무조건 실행 지속으로 처리하지 않도록 하자.