Struct async_tasks_recorder::AsyncTasksRecoder
source · pub struct AsyncTasksRecoder<T>{ /* private fields */ }
Expand description
Arc was used internally, so after clone
, the same TaskManager
was used,
which means you can share AsyncTasksRecoder
by clone.
§Usage
Launch a task with a unique task_id
and a Future
by launch.
Query the state of the task with its task_id
by query_task_state or query_task_state_quick.
§Further Propositions & Proofs
§P01
A task (or tasks with the same task_id
) wouldn’t be executed again after first success.
When a task fail, it wouldn’t break anything. Failure just means the task could be launched again, so if this proposition (P01) is true, there is almost nothing to worry about. For further discussion, please refer to P02.
From now on, only consider the situation of success.
working_tasks
play the role of lock,
which allow tasks with the same task_id
to execute remaining codes (after insert
& before remove
) only once.
And before remove
from working_tasks
, the succeeded task_id
has been in success_tasks
.
An equivalent pseudocode can be obtained.
working_tasks
become a mutex (maybe a spin lock) for onetask_id
.success_tasks
become an atomic boolean, which can only change from false to true.- An execution of a task becomes adding on an atomic int (
count
).
Therefore, if the count
is never greater than 1, it means that the task will only be called once.
let working_task_id = mutex::new();
let success_task_id = atomic(false);
let count = atomic(0);
launch_multi_thread {
working_task_id.lock();
if success_task_id.get() {
exit();
}
count.add(1);
success_task_id.set(true);
working_task_id.unlock();
}
assert_eq!(count.get(), 1);
Obviously, success_tasks.set(true)
can only be executed once.
After that, exit()
is always called.
This results in count.add(1)
being called only once, too. Q.E.D.
§P02
Task failure is not harmful for recorder.
Considering the situation of failure, the pseudocode becomes like this:
let working_task_id = mutex::new();
let success_task_id = atomic(false);
let failed_task_id = atomic(false); // Initially not in `failed_tasks`, but not important
let count = atomic(0);
launch_multi_thread {
working_task_id.lock();
if success_task_id.get() {
exit();
}
// Here should be `real_working`
failed_task_id.set(false); // So it shouldn't be `Failed`, just remove from `failed_tasks`
count.add(1);
if real_success {
success_task_id.set(true);
} else {
// `real_failed`
failed_task_id.set(true); // become `Failed`
}
working_task_id.unlock();
}
assert_eq!(count.get(), 1);
In a launch (critical section by working_tasks
), the initial value of failed is ignored.
Therefore, it’s not important whether failed_tasks
changes are atomic for launches.
From the perspective of query_task_state
,
failed_tasks
is only meaningful when task_id
is in it.
task_id
is in failed_tasks
only when it become real_failed
and before redo (next real_working
).
Very good.
§P03
No state would turn back to Not found
.
From the pseudocode in P02:
// entry `working_task_id`
if real_success {
success_task_id.set(true);
} else {
// `real_failed`
failed_task_id.set(true); // Become `Failed`
}
// leave `working_task_id`
It can be found that as long as the task has entered working_tasks
once,
when exiting working_tasks
,
the task must already be in one of the failed_tasks
or success_tasks
options.
So after first Working
, the task must be in one of tasks
,
then it won’t be Not found
again. Q.E.D.
Implementations§
source§impl<T> AsyncTasksRecoder<T>
impl<T> AsyncTasksRecoder<T>
sourcepub fn new_with_task_manager(task_manager: TaskManager<T>) -> Self
pub fn new_with_task_manager(task_manager: TaskManager<T>) -> Self
Create by TaskManager
sourcepub fn new_with_task_manager_arc(task_manager: Arc<TaskManager<T>>) -> Self
pub fn new_with_task_manager_arc(task_manager: Arc<TaskManager<T>>) -> Self
Create by Arc
of TaskManager
sourcepub async fn launch<Fut, R, E>(&self, task_id: T, task: Fut)
pub async fn launch<Fut, R, E>(&self, task_id: T, task: Fut)
Launch task that returns Result
.
The return value of task is ignored, so please use other methods to handle the return value, such as channel or shared variable.
task_id
: Uniquely mark a task. DifferentFuture
with the sametask_id
is considered the same task.task
: AFuture
to be executed automatically.
sourcepub async fn query_task_state(&self, task_id: &T) -> TaskState
pub async fn query_task_state(&self, task_id: &T) -> TaskState
Query the state of a task by task_id
.
Query priority of containers : success_tasks
-> failed_tasks
-> working_tasks
.
NOTE: working_tasks
usually has more contention.
If not found in all tasks, be NotFound
.
Only occurs before the launch or in a very short period of time after the first launch.
Note, if T
is String
, then parameter task_id
would be &String
instead of &str
.
sourcepub async fn query_task_state_quick(&self, task_id: &T) -> TaskState
pub async fn query_task_state_quick(&self, task_id: &T) -> TaskState
Return Working
if not in either success_tasks
or failed_tasks
.
No query in working_tasks
, so less contention.
Even when the task_id
’s launch have not occurred, return Working
.
Use this if you are certain that the task’s launch must occur at some point in the past or future,
and don’t care about when the launch occurs
(because first launch always turns into Working
at some point).
sourcepub fn get_task_manager_arc(&self) -> Arc<TaskManager<T>>
pub fn get_task_manager_arc(&self) -> Arc<TaskManager<T>>
Get a cloned Arc
of task_manager
.
Then you can do anything you want (Every containers are public).
sourcepub fn get_success_tasks_ref(&self) -> &HashSet<T>
pub fn get_success_tasks_ref(&self) -> &HashSet<T>
Get a reference of success_tasks
.
sourcepub fn get_working_tasks_ref(&self) -> &HashSet<T>
pub fn get_working_tasks_ref(&self) -> &HashSet<T>
Get a reference of working_tasks
.
sourcepub fn get_failed_tasks_ref(&self) -> &HashSet<T>
pub fn get_failed_tasks_ref(&self) -> &HashSet<T>
Get a reference of failed_tasks
.
Trait Implementations§
source§impl<T> Clone for AsyncTasksRecoder<T>
impl<T> Clone for AsyncTasksRecoder<T>
source§fn clone(&self) -> AsyncTasksRecoder<T>
fn clone(&self) -> AsyncTasksRecoder<T>
1.0.0 · source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source
. Read more