1292.42 Parallel 노드의 동시 자식 실행
1. 동시 자식 실행의 정의
Parallel 노드의 동시 자식 실행(concurrent child execution)이란, 단일 tick 내에서 모든 자식 노드에 tick 신호를 전달하여 각 자식이 매 tick마다 실행 기회를 부여받는 메커니즘을 의미한다. Sequence 노드와 Fallback 노드가 한 번에 하나의 자식에만 tick을 전달하는 것과 달리, Parallel 노드는 모든 자식을 매 tick마다 활성화한다. 이로 인해 복수의 자식이 동시에 Running 상태를 유지하며 각자의 작업을 진행할 수 있다 (Colledanchise & Ögren, Behavior Trees in Robotics and AI: An Introduction, 2018).
2. 논리적 동시성과 물리적 동시성의 구분
Parallel 노드의 동시 실행은 논리적 동시성(logical concurrency)에 해당하며, 물리적 동시성(physical concurrency)과 명확히 구분하여야 한다.
논리적 동시성: 단일 스레드에서 동일한 tick 내에 모든 자식에 순차적으로 tick을 전달한다. 각 자식은 왼쪽에서 오른쪽 순서로 tick을 수신하며, 미시적 수준에서는 순차적이다. 그러나 모든 자식이 매 tick마다 실행 기회를 받으므로, 거시적 수준에서는 동시적으로 진행되는 것으로 간주한다.
물리적 동시성: 복수의 스레드 또는 프로세스에서 자식 노드가 실제로 동시에 실행되는 것을 의미한다. 표준 행동 트리 실행 엔진은 단일 스레드에서 동작하므로, 이 의미의 동시성은 Parallel 노드의 기본 동작에 포함되지 않는다(Faconti, BehaviorTree.CPP Documentation, 2024).
이 구분은 행동 트리의 결정론적(deterministic) 실행 보장과 직결된다. 논리적 동시성에서는 자식의 tick 수신 순서가 항상 동일하므로, 동일한 환경 조건에서 항상 동일한 결과가 산출된다.
3. 동시 실행의 실행 흐름
Parallel 노드의 단일 tick 내 실행 흐름을 다음 예제를 통해 추적한다.
Parallel [P1]
├─ Action [A1]
├─ Action [A2]
└─ Action [A3]
단일 tick에서의 실행 순서는 다음과 같다.
- P1이 tick을 수신한다.
- P1이 A1에 tick을 전달한다. A1이 실행되고 반환 상태를 보고한다.
- P1이 A2에 tick을 전달한다. A2가 실행되고 반환 상태를 보고한다.
- P1이 A3에 tick을 전달한다. A3가 실행되고 반환 상태를 보고한다.
- P1이 모든 자식의 반환 상태를 집계하여 자신의 반환 상태를 결정한다.
이 과정은 매 tick마다 반복되며, 아직 완료되지 않은 자식(Running 상태)만이 후속 tick에서 tick을 수신한다.
4. 완료된 자식의 처리
Parallel 노드에서 이미 Success 또는 Failure를 반환한 자식은 완료된 것으로 간주되며, 후속 tick에서 다시 tick을 수신하지 않는다. 이 자식의 반환 상태는 내부적으로 기억되어 매 tick의 집계에 포함된다.
| Tick | A1 상태 | A2 상태 | A3 상태 | tick 수신 자식 |
|---|---|---|---|---|
| t_1 | Running | Running | Running | A1, A2, A3 |
| t_2 | Success | Running | Running | A2, A3 |
| t_3 | (기억: Success) | Success | Running | A3 |
| t_4 | (기억: Success) | (기억: Success) | Success | 없음 |
tick t_2 이후 A1은 더 이상 tick을 수신하지 않으며, A1의 Success 상태는 이후 모든 tick에서 집계에 포함된다. 이 메커니즘은 이미 완료된 작업의 불필요한 재실행을 방지한다 (Faconti, 2024).
5. 동시 실행에서의 자식 간 독립성
Parallel 노드의 동시 실행에서 각 자식은 원칙적으로 서로 독립적(independent)으로 실행된다. 한 자식의 반환 상태가 다른 자식의 tick 전달 여부에 영향을 미치지 않는다. 이는 Sequence 노드에서 선행 자식의 반환 상태가 후행 자식의 실행 여부를 결정하는 것과 대조적이다.
그러나 자식 노드가 블랙보드(blackboard)를 통해 데이터를 공유하는 경우, 동일한 tick 내에서 먼저 실행된 자식이 블랙보드에 기록한 데이터를 이후에 실행되는 자식이 읽을 수 있다. 이러한 간접적 의존성은 자식의 tick 수신 순서(왼쪽에서 오른쪽)에 의해 결정론적으로 처리된다.
6. 동시 실행의 실무적 활용 패턴
6.1 감시와 실행의 병행
Parallel [P1, M_S=1, M_F=1]
├─ Condition [C1: 안전 조건 지속 감시]
└─ Action [A1: 이동 수행]
C1은 매 tick마다 안전 조건을 평가하고, A1은 이동 작업을 진행한다. C1이 Failure를 반환하면 P1은 즉시 Failure를 반환하고 A1에 halt를 요청한다. 이 패턴은 행동 수행 중 안전 조건을 지속적으로 감시하는 용도로 활용된다.
6.2 독립적 작업의 병행 수행
Parallel [P1, M_S=3, M_F=1]
├─ Action [A1: 센서 A 데이터 수집]
├─ Action [A2: 센서 B 데이터 수집]
└─ Action [A3: 센서 C 데이터 수집]
세 센서의 데이터 수집을 동시에 진행하며, 세 작업이 모두 성공해야 P1이 성공을 반환한다. 하나라도 실패하면 나머지 작업을 중단한다 (Colledanchise & Ögren, 2018).
6.3 시간 제한이 있는 병행 작업
데코레이터 노드와 조합하여, 병행 작업에 시간 제한을 부여할 수 있다.
Parallel [P1]
├─ Timeout [3초]
│ └─ Action [A1: 장시간 작업]
└─ Action [A2: 단시간 작업]
A1에 3초의 시간 제한이 부여되며, 시간 초과 시 Timeout 데코레이터가 Failure를 반환한다.
7. 동시 실행의 제약 사항
Parallel 노드의 동시 실행에는 다음의 제약 사항이 존재한다.
첫째, 모든 자식이 단일 tick 내에서 순차적으로 실행되므로, 자식의 수가 증가하면 단일 tick의 실행 시간이 증가한다. tick 주기 내에 모든 자식의 실행이 완료되지 못하면 실시간성이 훼손될 수 있다.
둘째, 자식 간의 실행 순서가 왼쪽에서 오른쪽으로 고정되어 있으므로, 블랙보드를 통한 데이터 공유 시 순서 의존적인 동작이 발생할 수 있다. 이를 의도적으로 활용하거나, 자식 간 데이터 의존성을 최소화하는 설계가 필요하다.
셋째, Parallel 노드의 자식이 동일한 하드웨어 자원(액추에이터, 센서 등)을 동시에 사용하려는 경우, 자원 경합(resource contention)이 발생할 수 있다. 이러한 경합은 행동 트리 수준이 아닌 하위 시스템 수준에서 관리되어야 한다.
참고 문헌
- Colledanchise, M. & Ögren, P. (2018). Behavior Trees in Robotics and AI: An Introduction. CRC Press.
- Faconti, D. (2024). BehaviorTree.CPP Documentation. https://www.behaviortree.dev/