| Crates.io | taskorch |
| lib.rs | taskorch |
| version | 0.3.0 |
| created_at | 2025-07-09 15:59:17.865548+00 |
| updated_at | 2025-10-26 12:21:43.199464+00 |
| description | Concurrent Pool for task processing |
| homepage | |
| repository | https://github.com/hailongxu/taskorch |
| max_upload_size | |
| id | 1745060 |
| size | 137,612 |
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 IDs and instances.
Tasks can be executed in two distinct modes:
The task consists of two main parts:
Add only one of the following lines to your Cargo.toml:
# No logs, no color
taskorch = "0.3.0"
# With logging, and colored output
taskorch = {version="0.3.0", features=["log-info", "log-color"]}
Optional features can be enabled based on your needs (see Features).
An ID is required for each task, except for tasks that don't have any conditions. see [TaskId]
taskid_next().cond]Results from multi tasks [task1.result, task2.result, ..] are passed as inputs to a single task(cond#1,cond#2,..) using .bind_to()
see Example task N->1.
The result from a single task.result is distributed to the conditions of multiple tasks [task1.cond, task2.cond,..] using .bind_all_to()
see Example task 1->N (since v0.3.0).
.into_task().bind_to() to send the task result to a single target condaddr.bind_all_to() to distribute the multi-result from single task to multi target condaddr.⚠️ Prerequisite: Call
.map_tuple_with()first to map the single result into multiple outputs.
The second step is optional and can be skipped if the task does not produce any result.
NO parameter, NO taskid needed.
NO return, NO target condaddr required.
.into_task()Any function or closure by calling .into_task() will complete constructing a task;
# use taskorch::{TaskBuildNew,TaskId};
// with an explicit taskid = 1
let task = (|_:i32|{3}, TaskId::from(1)).into_task();
// with no explicit taskid, the system will auto-generate one when submitting !!!!
let task = (|_:i32|{3}).into_task();
Exit task creation
The only difference here is the use of .into_exit_task() instead of .into_task().
.bind_to()# use taskorch::{TaskBuildNew,TaskId};
let task = (|i16,i32|{}, TaskId::from(1)).into_task(); // task#1 with 2 cond (#0 i16,#1 i32)
let task1 = (||{2}).into_task().bind_to(task.input_ca::<0>()); // task1 -> task
let task2 = (||{3}).into_task().bind_to(task.input_ca::<1>()); // task2 -> task
.bind_all_to()# use taskorch::{TaskBuildNew,TaskId};
let task1 = (|_:i16|{3}, TaskId::from(1)).into_task(); // task#1 with cond<i16>#0
let task2 = (|_:i32|{3}, TaskId::from(2)).into_task(); // task#2 with cond<i32>#0
let task = (|| 2i16).into_task() // Task output: i16
// Transforms input(task single output `i16`) into multiple outputs
.map_tuple_with(|a: i16| (1i16, 2i32))
// Output binding:
// - result.#0: i16 (bound to task1.input<0>)
// - result.#1: i32 (bound to task2.input<0>)
// Type safety: All bindings are verified at compile time
.bind_all_to((task1.input_ca::<0>(), task2.input_ca::<0>()));
Starting with v0.3, type checking for binding outputs to inputs is enforced at compile time rather than at runtime as in previous versions. This shift enables early error detection during development, and reduces debugging time.
As this project is currently in early active development, the API is highly unstable and will change in subsequent versions.
use taskorch::{Pool, Queue, TaskBuildNew};
// [A] => [B1, B2] ## 1->N
// [B1, B2] => [Exit] ## N->1
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
let task = (|| println!("task='free': Hello, 1 2 3 ..")).into_task();
let _ = submitter.submit(task);
// an exit task with cond(#0 i32, #1 str)
let exit = submitter
.submit(
(|a: i32, msg: &str| println!("task='exit': received ({a},{msg:?}) and EXIT"))
.into_exit_task(),
)
.take();
// N->1 : pass i32 to exit-task.p0
let b1 = (|a: i32| {
println!("task='B1': pass ('{a}') to task='exit'");
a
})
.into_task()
.bind_to(exit.input_ca::<0>());
let b1 = submitter.submit(b1).take();
// N->1 : pass str to exit task.p1
let b2 = (|msg: &'static str| {
println!("task='B2': recv ('{msg}') and then pass ('{msg}') to task='exit'");
msg
})
.into_task()
.bind_to(exit.input_ca::<1>());
let b2 = submitter.submit(b2).take();
// 1->N : map result to task-b1 and task-b2
let b3 = (||())
.into_task()
.map_tuple_with(move |_: ()| {
println!("task='A': map `()=>(i32,&str)` and then pass (10,'exit') to task=['B1','B2']");
(10, "exit")
})
.bind_all_to((b1.input_ca::<0>(), b2.input_ca::<0>()));
let _ = submitter.submit(b3);
// 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"
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 log level 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:
Pool was createdThis is a relative time (not absolute wall-clock time), designed for analyzing task sequences.