145 lines
5.0 KiB
Rust
145 lines
5.0 KiB
Rust
// 独立 Tokio 参照只实现本组一层任务工作负载,不调用 Dever 调度器。
|
|
// 任务和 worker 分别限流;遇到失败或取消仍领取所有 JoinHandle,已启动阻塞工作不强停。
|
|
use std::{sync::Arc, time::Duration};
|
|
use tokio::{runtime, sync::Semaphore, task::JoinHandle};
|
|
use tokio_util::sync::CancellationToken;
|
|
|
|
struct NativeTasks {
|
|
runtime: runtime::Runtime,
|
|
workers: Arc<Semaphore>,
|
|
tasks: Arc<Semaphore>,
|
|
}
|
|
|
|
fn task_fault(_: impl std::fmt::Debug) -> Fault {
|
|
&FaultInfo {
|
|
source: "task-reference",
|
|
line: 1,
|
|
column: 1,
|
|
message: "task failure",
|
|
}
|
|
}
|
|
|
|
fn native_total(values: &[i64]) -> Result<i64, Fault> {
|
|
values.iter().try_fold(0i64, |total, value| {
|
|
total
|
|
.checked_add(*value)
|
|
.ok_or_else(|| task_fault("integer overflow"))
|
|
})
|
|
}
|
|
|
|
impl NativeTasks {
|
|
fn new() -> Self {
|
|
Self {
|
|
runtime: runtime::Builder::new_multi_thread()
|
|
.worker_threads(2)
|
|
.max_blocking_threads(2)
|
|
.enable_time()
|
|
.build()
|
|
.unwrap(),
|
|
workers: Arc::new(Semaphore::new(2)),
|
|
tasks: Arc::new(Semaphore::new(8)),
|
|
}
|
|
}
|
|
|
|
fn start(
|
|
&self,
|
|
values: Vec<i64>,
|
|
asynchronous: bool,
|
|
cancel: CancellationToken,
|
|
) -> JoinHandle<Result<i64, Fault>> {
|
|
let admission = self.tasks.clone().try_acquire_owned().unwrap();
|
|
let workers = self.workers.clone();
|
|
tokio::spawn(async move {
|
|
let result = if asynchronous {
|
|
tokio::select! {
|
|
biased;
|
|
result = async { native_total(&values) } => result,
|
|
() = cancel.cancelled() => Err(task_fault("cancelled")),
|
|
}
|
|
} else {
|
|
let worker = tokio::select! {
|
|
biased;
|
|
() = cancel.cancelled() => return Err(task_fault("cancelled")),
|
|
worker = workers.acquire_owned() => worker.unwrap(),
|
|
};
|
|
let result = tokio::task::spawn_blocking(move || native_total(&values))
|
|
.await
|
|
.map_err(task_fault)?;
|
|
drop(worker);
|
|
result
|
|
};
|
|
drop(admission);
|
|
result
|
|
})
|
|
}
|
|
|
|
fn pair(&self, values: &[i64], asynchronous: bool) -> Result<i64, Fault> {
|
|
self.runtime.block_on(async {
|
|
let cancel = CancellationToken::new();
|
|
let first = self.start(values.to_vec(), asynchronous, cancel.child_token());
|
|
let second = self.start(values.to_vec(), asynchronous, cancel.child_token());
|
|
let first = first.await.map_err(task_fault).and_then(|value| value);
|
|
if first.is_err() {
|
|
cancel.cancel();
|
|
}
|
|
let second = second.await.map_err(task_fault).and_then(|value| value);
|
|
cancel.cancel();
|
|
first?
|
|
.checked_add(second?)
|
|
.ok_or_else(|| task_fault("integer overflow"))
|
|
})
|
|
}
|
|
|
|
fn blocking(&self, values: &[i64], sleep: bool) -> Result<i64, Fault> {
|
|
let values = values.to_vec();
|
|
self.runtime.block_on(async {
|
|
let worker = self.workers.clone().acquire_owned().await.unwrap();
|
|
let result = tokio::task::spawn_blocking(move || {
|
|
if sleep {
|
|
std::time::Instant::now()
|
|
.checked_add(Duration::ZERO)
|
|
.ok_or_else(|| task_fault("sleep deadline"))?;
|
|
std::thread::sleep(Duration::ZERO);
|
|
}
|
|
native_total(&values)
|
|
})
|
|
.await
|
|
.map_err(task_fault)?;
|
|
drop(worker);
|
|
result
|
|
})
|
|
}
|
|
|
|
fn cancel(&self) -> Result<i64, Fault> {
|
|
self.runtime.block_on(async {
|
|
let admission = self.tasks.clone().try_acquire_owned().unwrap();
|
|
let cancel = CancellationToken::new();
|
|
let child = cancel.child_token();
|
|
let task = tokio::spawn(async move {
|
|
let deadline = tokio::time::Instant::now()
|
|
.checked_add(Duration::from_millis(60000))
|
|
.unwrap();
|
|
tokio::select! {
|
|
biased;
|
|
() = tokio::time::sleep_until(deadline) => panic!("cancelled timer completed"),
|
|
() = child.cancelled() => (),
|
|
}
|
|
drop(admission);
|
|
});
|
|
cancel.cancel();
|
|
task.await.map_err(task_fault)?;
|
|
Ok(1)
|
|
})
|
|
}
|
|
|
|
fn timer(&self) -> Result<i64, Fault> {
|
|
self.runtime.block_on(async {
|
|
let deadline = tokio::time::Instant::now()
|
|
.checked_add(Duration::ZERO)
|
|
.ok_or_else(|| task_fault("sleep deadline"))?;
|
|
tokio::time::sleep_until(deadline).await;
|
|
Ok(1)
|
|
})
|
|
}
|
|
}
|