Expand description
§taskorch
§System Composition
The entire concurrency library can generally be divided into four main components:
- Task — The minimal unit of execution, built from a fn or closure along with runtime metadata.
- Queue — The queue holds tasks that are waiting to be processed. It acts as a buffer where tasks are stored until they can be executed.
- Threads — Threads are responsible for executing the tasks retrieved from the queue.
- Resource Pool — Responsible for the lifecycle management of both the Queue and the Threads, establishing a mapping between names and instances.
§Task
§Task Modes
Tasks can be executed in two distinct modes:
- Independent: Runs freely without constraint.
- Conditional: Executes only when all conditions are satisfied.
§Task Flow
- Activation:
A task is scheduled once all its required conditions are fulfilled. - Execution:
The task runs and computes its return value. - Data Passing:
If atarget anchor
is configured, the return value will be passed on to another task.
Key Notes:
- Conditions correspond to the function’s parameters (0-indexed).
§Task ID Assignment
- Explicit ID: You can provide your own ID using a generator or by calling
taskid_next()
. - Auto-generated: If you omit specifying an ID, the system will automatically assign one.
§Building a Task (3-Step Process)
- Prepare: Define a function or closure.
- Create: Create the task chained by
.into_task()
. - Notify (Optional): Chain tasks by calling
to()
to set atarget anchor
.
This step can be skipped if the task does not produce any output.
§Usage
Add only one of the following lines to your Cargo.toml
:
# No logs, no color
taskorch = "0.2.1"
# With logging, and colored output
taskorch = {version="0.2.1", features=["log-info", "log-color"]}
Optional features can be enabled based on your needs (see Available Features).
§Task Creation Code
§Note
NO parameter
, NO taskid
needed.
NO return
, NO target anchor
required.
Case 1: [ No parameter, No return ]
let task =
(||{}) // <1> Define the body
.into_task(); // <2> Create a task from the given closure.
// <3> `to()` skipped, as there is no return value
Case 2: [ No parameter, With return ]
let task =
(||{3}) // <1> Define the body
.into_task() // <2> Create a task from the given closure.
.to(2,0); // <3> Set target;
// the return value will be forwarded to task #2, condition #0.
let task =
(||{3}) // <1> ..
.into_task(); // <2> ..
// <3> `to()` skipped, the return value dropped
Case 3: [ With parameter, No return ]
let task =
(|_:i8|{}) // <1> Define the body, taskid is auto-generated.
.into_task(); // <2> Create a task from the given closure.
// <3> `to()` skipped, as there is no return value
let task =
(|_:i8|{}, 1) // <1> Define the body, with an explicit taskid.
.into_task(); // <2> ..
// <3> ..
Case 4: [ With parameter, With return ]
let task =
(|_:i8|{3}) // <1> Define the body, taskid is auto-generated.
.into_task(); // <2> Create a task from the given closure.
// <3> `to()` skipped, the return value dropped
let task =
(|_:i8|{3}, 1) // <1> Define the body, with an explicit taskid.
.into_task(); // <2> ..
// <3> ..
let task =
(|_:i8|{3}) // <1> Define the body, taskid is auto-generated.
.into_task() // <2> Create a task from the given closure.
.to(2,0); // <3> Set target;
// the return value will be forwarded to task #2 and cond #0
let task =
(|_:i8|{3}, 1) // <1> Define the body, with an explicit taskid.
.into_task() // <2> ..
.to(2,0); // <3> ..
Exit task creation
The only difference here is the use of .into_exit_task()
instead of .into_task()
.
§⚠️ Type cast NOTE
❗ Error-prone operation!
When forwarding a task result to a conditional task’s condition point:
- Ensure the result type must be identical to the condition type.
- Violation will trigger
panic
!
// Sample code explanation
let cc = |a:i32,b:i8|{}; // the type of cond #0 is `i32`
// the type of cond #1 is `i8`
let f0 = ||5i32; // the return type is `i32`
let f1 = ||5i8; // the return type is `i8`
let task_cc = (cc,1).into_task(); // taskid is explicitly set to 1
let task_f0 = f0.into_task().to(1,0); // *** return type `i32` === cond #0 type `i32` ***
let task_f1 = f1.into_task().to(1,1); // *** return type `i8` === cond #1 type `i8` ***
§⚠️ API NOTE
As this project is currently in early active development, the API is highly unstable and will change in subsequent versions.
§Example
use taskorch::{Pool, Queue, TaskBuildNew, TaskBuildOp};
// create 3 tasks and run
fn main() {
println!("----- test task orch -----");
// Step#1. create a Pool
let mut pool = Pool::new();
// Step#2. create a queue
let qid = pool.insert_queue(&Queue::new()).unwrap();
let submitter = pool.task_submitter(qid).unwrap();
// Step#3. create tasks
// an indepent task
submitter.submit((||println!("free-task: Hello, 1 2 3 ..")).into_task());
// an exit task with ONE str cond
let id_exit = submitter.submit(
(|msg:&str|
println!("exit-task: received ({msg:?}) and EXIT")
).into_exit_task()
);
// another task pass message to exit task
submitter.submit(
(||{
const MSG: &'static str = "exit";
println!("task 'AA': I pass [\"{MSG}\"] to exit-task to exit");
MSG
}).into_task().to(id_exit, 0)
);
// Step#4. start a thread and run
pool.spawn_thread_for(qid);
// Step#5. wait until all finished
pool.join();
}
For a more complex demo, see the usage
and spsc
example.
cargo run --example usage --features="log-trace,log-color"
cargo run --example spsc --features="log-trace,log-color"
§Available Features
All logs are compile-time controlled and have zero runtime overhead when disabled.
log-error
: Logs ERROR level onlylog-warn
: Logs WARN level and abovelog-info
: Logs INFO level and abovelog-debug
: Logs DEBUG level and abovelog-trace
: Logs TRACE level and above (most verbose)log-color
: Adds ANSI color to log messages in the terminal
⚠️ Note:
These features are mutually exclusive - only one or none can be enabled at a time.
No logs are emitted by default.
Color is disabled by default.
§🕒 Timestamp Format in Logs
The timestamp used in logs is measured from the earliest of the following events:
- The time when the first log message was emitted
- The time when the first
Pool
was created
This is a relative time (not absolute wall-clock time), designed for analyzing task sequences.
Structs§
- Anchor
- Represents a position where a condition occurs.
- Jhandle
- a handle to a thread spawned for queue
- Pool
- Pool, a container that holds and managers all resources, such as threads and queues
- Queue
- A queue holding tasks awaiting scheduling by threads
- Task
Currier - The carrier of the task, used to create and invoke its functionality.
- Task
Submitter - Handles task submission to a specific queue
Enums§
- Kind
- Defines the behavior type for tasks.
Traits§
- Task
Build New - A builder trait for constructing tasks with an optional task ID.
- Task
Build Op - TaskBuildOp provides target anchor configuration.
Functions§
- spawn_
thread - taskid_
next - Generate a task ID