문제상황
콜백 A, B, C가 있을 때, 콜백 A가 n초 동안 스레드를 점유하면, 콜백 B와 C는 그동안 실행되지 않음
-> 특히, B와 C가 센서 데이터를 처리하는 콜백이라면, 데이터가 제때 업데이트되지 않아 지연이나 누락 문제가 발생할 수 있음
=> 스레드 병렬 처리로 해결 가능

from rclpy.executors import SingleThreadedExecutor, MultiThreadedExecutor
def main(args=None):
rclpy.init(args=args)
node = ClassNode()
# Create a single-threaded executor
executor = SingleThreadedExecutor()
executor.add_node(node)
# Create a multi-threaded executor
executor = MultiThreadedExecutor(num_threads=3)
executor.add_node(node)
try:
executor.spin()
finally:
executor.shutdown()
executor.destroy_node()
rclpy.shutdown()


from rclpy.callback_groups import MutuallyExclusiveCallbackGroup
class Example(Node):
def __init__(self):
super().__init__('example')
### Callback group ###
# group1의 콜백들은 병렬 처리 가능
self.group1 = ReentrantCallbackGroup()
# group2 내부의 콜백은 하나씩만 처리 가능
self.group2 = MutuallyExclusiveCallbackGroup()
# Subscriber
self.function1 = self.create_subscription(msg,'topic1',self.call_back1, 10,callback_group=self.group1)
self.function2 = self.create_subscription(msg,'topic2',self.call_back2, 10,callback_group=self.group1)
# Timer
self.function2 = self.create_timer(0.3, self.call_back3, callback_group=self.group2)
def call_back1(self, msg):
self.get_logger().info("call_back1")
def call_back2(self, msg):
self.get_logger().info("call_back2")
def call_back3(self, msg):
self.get_logger().info("call_back3")
참고 : CPU의 논리 코어(Logical Core) 개수 확인
ㄴ ROS 2 노드를 실행할 때 사용할 수 있는 스레드/코어 수
- Linux : cat /proc/cpuinfo | grep processor | wc -l
- Python : psutil.cpu_count(logical=True)
콜백이 가볍다면(read | logging 등) 싱글 스레드로 충분하지만, 고속 센서나 무거운 처리가 있다면 Reentrant + MultiThreadedExecutor 조합이 필요
병목이 생길 수 있는 경우
- 센서 자체가 고주기(>100Hz) 인 경우
- 이미지 처리, 딥러닝 모델 호출, 파일 저장, 경로 탐색 같은 무거운 작업 시
- 콜백 간에 잠금(lock) 구조가 걸릴 경우
| 상황 | Callback Group | Executor |
|---|---|---|
| 단순 제어 로직 | MutuallyExclusive | SingleThreadedExecutor |
| 센서 다수 / 빠른 주기 | Reentrant | MultiThreadedExecutor |
| 이미지 처리 / 딥러닝 | Reentrant | MultiThreadedExecutor |
| 공유 자원 접근 있음 | MutuallyExclusive | 어떤 Executor든 OK |