1292.101 비동기적 실행 의미론

1. 비동기적 실행 의미론의 정의

비동기적 실행 의미론(asynchronous execution semantics)이란, 행동 트리의 액션 노드가 단일 tick 내에서 실행을 완료하지 않고 Running 상태를 반환하여, 다수의 tick에 걸쳐 행동을 지속하는 실행 모델이다. 비동기적 실행에서 액션 노드의 실제 계산은 별도의 실행 흐름(스레드, 코루틴, 또는 외부 프로세스)에서 수행되며, tick 함수는 해당 행동의 현재 진행 상태만을 확인하여 반환한다 (Colledanchise & Ögren, Behavior Trees in Robotics and AI: An Introduction, 2018).

2. 비동기적 실행의 필요성

로봇 시스템에서 대부분의 행동은 단일 tick 내에서 완료될 수 없다. 경로 추종, 물체 파지, 센서 데이터 수집 등의 행동은 수 초에서 수 분에 이르는 시간을 필요로 하며, 이러한 행동을 동기적으로 실행하면 tick이 장시간 블로킹되어 다른 행동의 평가와 반응이 불가능해진다. 비동기적 실행 의미론은 이 문제를 해결한다.

동기적 실행의 제약비동기적 실행에 의한 해결
장기 행동 시 tick 블로킹Running 반환으로 즉시 tick 완료
조건 재평가 불가매 tick에서 조건 재평가 가능
실시간 응답 불가tick 주기에 맞춘 주기적 응답
안전 조건 검사 지연안전 조건의 주기적 검사 보장

3. 비동기적 tick의 실행 흐름

비동기적 실행에서 액션 노드는 다음의 생명주기를 따른다.

function AsyncAction.tick():
    if first_tick:
        // 비동기 작업 시작
        start_async_operation()
        return Running

    if async_operation_completed():
        if operation_succeeded():
            return Success
        else:
            return Failure

    // 작업 진행 중
    return Running

다수의 tick에 걸친 비동기 액션의 실행 추적은 다음과 같다.

Root
 └─ Sequence
      ├─ Condition [C1]
      └─ AsyncAction [Navigate]

Tick 1: C1 → Success, Navigate.onStart() → Running   ← 비동기 작업 시작
Tick 2: C1 → Success, Navigate.onRunning() → Running  ← 작업 진행 중
Tick 3: C1 → Success, Navigate.onRunning() → Running  ← 작업 진행 중
Tick 4: C1 → Success, Navigate.onRunning() → Success  ← 작업 완료

4. 비동기 실행의 구현 모델

비동기적 실행 의미론은 다양한 구현 모델을 통해 실현된다.

4.1 별도 스레드 모델

액션 노드가 별도의 스레드에서 행동을 수행하고, tick 함수는 해당 스레드의 완료 여부를 확인하여 Running, Success, 또는 Failure를 반환한다. BehaviorTree.CPP 라이브러리의 ThreadedAction이 이 모델을 구현한다 (Faconti, BehaviorTree.CPP Documentation, 2024).

function ThreadedAction.onStart():
    thread = spawn_thread(execute_action)
    return Running

function ThreadedAction.onRunning():
    if thread.is_finished():
        return thread.result()
    return Running

4.2 상태 기계 모델

액션 노드가 내부 상태 기계를 유지하고, 매 tick에서 상태 기계의 현재 상태에 따라 점진적으로 작업을 진행한다. 별도의 스레드를 사용하지 않으므로 동시성 문제가 발생하지 않는다.

4.3 외부 서비스 모델

액션 노드가 ROS2 액션 서버 등 외부 서비스에 요청을 보내고, 매 tick에서 서비스의 완료 여부를 폴링(polling)한다. 실제 계산은 외부 프로세스에서 수행되므로, tick 함수의 실행 시간이 최소화된다.

구현 모델장점단점
별도 스레드기존 블로킹 코드 재사용 가능동시성 제어 필요
상태 기계단일 스레드, 결정론적복잡한 행동의 구현 어려움
외부 서비스프로세스 격리, 분산 실행통신 지연, 오류 처리 복잡

5. Running 상태의 전파

비동기적 실행에서 Running 상태는 리프 노드에서 루트 노드까지 역전파된다. 제어 흐름 노드는 자식이 Running을 반환하면 자신도 Running을 반환하며, 이는 트리 전체가 현재 진행 중인 행동이 존재함을 나타낸다.

Root ← Running
 └─ Sequence ← Running
      ├─ Condition [C1] → Success     (완료)
      └─ AsyncAction [A1] → Running   (진행 중)

6. 비동기적 실행과 Halt

비동기적 실행에서 Halt의 처리는 동기적 실행보다 복잡하다. Running 상태의 비동기 액션 노드가 halt되면, 진행 중인 비동기 작업을 안전하게 중단해야 한다.

function AsyncAction.halt():
    if thread is running:
        request_thread_stop()
        wait_for_thread_completion()   // 또는 타임아웃 후 강제 종료
    cleanup_resources()
    set_status(Idle)

스레드의 강제 종료는 자원 누수나 데이터 손상을 유발할 수 있으므로, 협력적 중단(cooperative cancellation) 방식이 권장된다. 비동기 작업은 주기적으로 중단 요청 플래그를 확인하고, 요청이 있으면 안전하게 종료한다 (Faconti, 2024).

7. 비동기적 실행과 메모리 있는 제어 흐름

비동기적 실행에서 SequenceWithMemory(메모리 있는 Sequence)는 중요한 역할을 한다. 일반 Sequence는 매 tick에서 첫 번째 자식부터 재평가하지만, 메모리 있는 Sequence는 이전 tick에서 Running을 반환한 자식부터 재개한다. 이는 이미 성공한 자식을 불필요하게 재평가하는 것을 방지한다.

SequenceWithMemory
 ├─ Action [A1]     Tick 1: Success   Tick 2: (건너뜀)
 ├─ Action [A2]     Tick 1: Running   Tick 2: Success
 └─ Action [A3]     Tick 1: (미평가)  Tick 2: Running

8. 로봇 공학에서의 의의

비동기적 실행 의미론은 로봇 시스템의 행동 트리에서 사실상 표준적인 실행 모델이다. 로봇의 물리적 행동은 본질적으로 시간이 소요되는 비동기적 과정이므로, 비동기적 실행 의미론 없이는 행동 트리를 통한 로봇 제어가 실질적으로 불가능하다. 비동기적 실행은 장기 실행 행동의 진행 중에도 안전 조건의 주기적 검사와 우선순위 높은 행동으로의 전환을 가능하게 하며, 이는 로봇의 반응성과 안전성의 핵심 요건이다 (Colledanchise & Ögren, 2018).


참고 문헌

  • 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/