Executor
Interface Overview
For the specific concept of the executor, please refer to the introduction in Executor - CPP Interface. This section only describes the concrete syntax of the executor functionality in AimRT Python. A module can obtain an ExecutorManagerRef
handle by calling the GetExecutorManager()
interface of the CoreRef
handle, which provides a simple interface to get an Executor
:
GetExecutor(str)->ExecutorRef
: Obtain an executor handle by name;
Executors in AimRT have some inherent properties, most of which are related to the executor type and do not change during runtime. These inherent properties include:
Executor Type: A string field identifying the type of the executor at runtime.
Within a single AimRT instance, there can be multiple types of executors. AimRT officially provides several executors, and plugins can also provide new executor types.
For details on executor types and their characteristics, please refer to the
executor
configuration section in the deployment phase.During logical development, you should not focus too much on the actual runtime executor type; simply implement business logic according to the abstract executor interface.
Executor Name: A string field identifying the name of the executor at runtime.
Within a single AimRT process, the name uniquely identifies an executor.
All executor instance names are determined at runtime through configuration. For details, please refer to the
executor
configuration section in the deployment phase.You can obtain an executor with a specified name via the
GetExecutor
method ofExecutorManagerRef
.
Thread Safety: A boolean value indicating whether this executor is thread-safe.
Usually related to the executor type.
A thread-safe executor guarantees that tasks submitted to it will not run concurrently; otherwise, no such guarantee is provided.
Support for Time-based Scheduling: A boolean value indicating whether this executor supports time-based scheduling interfaces, namely the
ExecuteAt
andExecuteAfter
interfaces.If this executor does not support time-based scheduling, calling the
ExecuteAt
orExecuteAfter
interfaces will throw an exception.
Users can call the GetExecutor
method in ExecutorManagerRef
to obtain an ExecutorRef
handle with a specified name to use executor-related functionality. The core interfaces and usage instructions for ExecutorRef
are as follows:
Type()->str
: Get the type of the executor.Name()->str
: Get the name of the executor.ThreadSafe()->bool
: Return whether this executor is thread-safe.IsInCurrentExecutor()->bool
: Determine whether the current environment is within this executor when this function is called.Note: If it returns true, the current environment is definitely within this executor; if it returns false, the current environment may or may not be within this executor.
SupportTimerSchedule()->bool
: Return whether this executor supports time-based scheduling interfaces, namely theExecuteAt
andExecuteAfter
interfaces.Execute(Task)
: Submit a task to this executor for immediate execution upon scheduling.The parameter
Task
can be simply regarded as a task closure with the signature()->void
.This interface can be called during the Initialize/Start phase, but the executor only guarantees to start executing after the Start phase. Therefore, calling this interface before the Start phase may only enqueue the task into the executor’s task queue without immediate execution, and the task will start executing only after the Start phase.
Now()->datetime
: Get the time in this executor’s time system.For general executors, this returns the standard system time.
For some special executors with time-scaling functionality, this may return processed time.
ExecuteAt(datetime, Task)
: Execute a task at a specific time point.The first parameter - time point, is based on this executor’s time system.
The second parameter
Task
can be simply regarded as a task closure with the signature()->void
.If this executor does not support time-based scheduling, calling this interface will throw an exception.
This interface can be called during the Initialize/Start phase, but the executor only guarantees to start executing after the Start phase. Therefore, calling this interface before the Start phase may only enqueue the task into the executor’s task queue without immediate execution, and the task will start executing only after the Start phase.
ExecuteAfter(timedelta, Task)
: Execute a task after a certain duration.The first parameter - duration, is based on this executor’s time system.
The second parameter
Task
can be simply regarded as a task closure with the signature()->void
.If this executor does not support time-based scheduling, calling this interface will throw an exception.
This interface can be called during the Initialize/Start phase, but the executor only guarantees to start executing after the Start phase. Therefore, calling this interface before the Start phase may only enqueue the task into the executor’s task queue without immediate execution, and the task will start executing only after the Start phase.
Usage Example
Below is a simple usage example demonstrating how to obtain an executor handle and submit a simple task to the executor for execution:
import aimrt_py
import datetime
class HelloWorldModule(aimrt_py.ModuleBase):
def __init__(self):
super().__init__()
self.logger = aimrt_py.LoggerRef()
self.work_executor = aimrt_py.ExecutorRef()
def Initialize(self, core):
assert(isinstance(core, aimrt_py.CoreRef))
self.logger = core.GetLogger()
# Get executor with name 'work_thread_pool'
self.work_executor = core.GetExecutorManager().GetExecutor("work_thread_pool")
assert(isinstance(work_executor, aimrt_py.ExecutorRef))
# Check for executor 'work_thread_pool'
if (not self.work_executor or not self.work_executor.SupportTimerSchedule()):
aimrt_py.error(self.logger, "Get executor 'work_thread_pool' failed.")
return False
return True
def Start(self):
def test_task():
aimrt_py.info(self.logger, "run test task.")
# Deliver to the 'work_executor' and execute immediately
self.work_executor.Execute(test_task)
# Deliver to the 'work_executor' and execute after a period of time
self.work_executor.ExecuteAfter(datetime.timedelta(seconds=1), test_task)
# Deliver to the 'work_executor' and execute at a certain point in time
self.work_executor.ExecuteAt(datetime.datetime.now() + datetime.timedelta(seconds=2), test_task)
return True