pub struct AsyncTask<P: AsyncTaskPoolExt<O> + AsyncTaskPool<O>, O: Default + 'static = ()> { /* private fields */ }Expand description
异步任务及其运行时调度/生命周期状态。
§运行时契约
运行时托管任务是一次性的:其 Future 被持续轮询,首次返回 Ready 后永久完成。
运行时任务通过私有原子状态合并重复唤醒、排除并发轮询,并拒绝迟到唤醒。公开
get_inner/set_inner 选择旧手工驱动契约,包括显式的低层替换/复用能力,因此
既有自定义驱动无需新增特征方法。
构造函数只创建一个逻辑上的首次轮询义务,并不执行物理入队。运行时或自定义任务池
必须通过既有 push* 接口把新任务准确入队一次。Waker 用于在首次提交后安排后续
轮询,不能替代首次入队。
§示例
use std::sync::Arc;
use futures::FutureExt;
use pi_async_rt::rt::{
AsyncRuntime, AsyncTask, AsyncTaskPool,
single_thread::SingleTaskRunner,
};
let runner = SingleTaskRunner::<()>::default();
let runtime = runner.startup().unwrap();
let task = Arc::new(AsyncTask::new(
runtime.alloc::<()>(),
runtime.shared_pool(),
0,
Some(async {}.boxed()),
));
runtime.shared_pool().push(task).unwrap();
runner.run_once().unwrap();future 锁只覆盖取出或恢复装箱的 Future;绝不会跨越 Future::poll、任务池访问、
工作线程通知、用户回调/析构、I/O 或 FFI。运行时状态操作为 O(1)、无分配且无锁,
但比较并交换循环不具备无等待性,在竞争唤醒/轮询状态持续推进时可能重试。任务不是
repr(C),不提供稳定的 FFI/Rust 布局 ABI。
§布局与内存
在已验收的 x86_64 目标上,加入内联调度状态后,
AsyncTask<StealableTaskPool<()>, ()> 为 96 字节,之前的实现为 80 字节。
一字节状态跨过了该特化的 16 字节对齐边界,因此实际内联增量是 16 字节,而不是
一字节。百万个同时存活的任务会增加 16,000,000 字节(约 15.26 MiB)任务本体
存储。这是并发存活/保留成本,不会按历史累计执行过的任务数增长。
状态不会新增独立堆分配。Arc 管理信息、装箱的 Future、任务句柄、context 负载和
队列存储仍是独立的既有成本,不包含在 96 字节本体内。分配器尺寸分级和队列
容量会使实际 RSS 与逻辑本体增量不同。若要把本体恢复到 80 字节,需要重新组织
context/state 表示;该优化会触及 V8 敏感的所有权表示,必须单独设计、审查和
验证下游,因此本轮明确延期。
§安全性
托管轮询所有权由 state 同步,Future 所有权由 future 同步。既有 TaskId 和
context 安全要求不变。调用方不得并发手工轮询同一任务,也不得从任务池窃取
运行时所有的任务。
Implementations§
Source§impl<P: AsyncTaskPoolExt<O> + AsyncTaskPool<O, Pool = P>, O: Default + 'static> AsyncTask<P, O>
impl<P: AsyncTaskPoolExt<O> + AsyncTaskPool<O, Pool = P>, O: Default + 'static> AsyncTask<P, O>
Sourcepub fn new(
uid: TaskId,
pool: Arc<P>,
priority: usize,
future: Option<BoxFuture<'static, O>>,
) -> AsyncTask<P, O>
pub fn new( uid: TaskId, pool: Arc<P>, priority: usize, future: Option<BoxFuture<'static, O>>, ) -> AsyncTask<P, O>
构造一个一次性异步任务。
任务初始带有一个托管轮询义务。若任务进入本库运行时,私有驱动会保证唤醒
合并和独占轮询。调用公开 get_inner 或 set_inner 会选择旧手工驱动模式,
但不改变这两个方法的签名或值语义。
构造时间复杂度为 O(1),除参数已经拥有的值外不新增分配;不执行队列操作、 唤醒、轮询、加锁、I/O 或回调。每个值拥有一个 TaskId,因此构造不是幂等操作。
Sourcepub fn with_context<C: 'static>(
uid: TaskId,
pool: Arc<P>,
priority: usize,
future: Option<BoxFuture<'static, O>>,
context: C,
) -> AsyncTask<P, O>
pub fn with_context<C: 'static>( uid: TaskId, pool: Arc<P>, priority: usize, future: Option<BoxFuture<'static, O>>, context: C, ) -> AsyncTask<P, O>
构造一个带调用方 context 的一次性任务。
调度和唤醒语义与 AsyncTask::new 相同。本函数为 context 执行一次 Box
分配,因此构造的时间和空间复杂度均为 O(1)。它不入队、不轮询、不唤醒、
不获取运行时锁、不执行用户代码、不执行 I/O,也不接触 FFI。保存的 context
继续服从既有所有者线程/context 访问契约。
Sourcepub fn with_runtime_and_context<RT, C>(
runtime: &RT,
priority: usize,
future: Option<BoxFuture<'static, O>>,
context: C,
) -> AsyncTask<P, O>where
RT: AsyncRuntime<O, Pool = P>,
C: Send + 'static,
pub fn with_runtime_and_context<RT, C>(
runtime: &RT,
priority: usize,
future: Option<BoxFuture<'static, O>>,
context: C,
) -> AsyncTask<P, O>where
RT: AsyncRuntime<O, Pool = P>,
C: Send + 'static,
构造一个绑定到 runtime 且携带调用方 context 的任务。
返回值随后由本库运行时驱动消费时属于托管任务,这也包括
pi_v8::VmTaskPool 等外部定时器适配器。公开 get/set 仍会选择旧手工驱动。
构造为 O(1),执行既有 runtime.alloc TaskHandle 分配、一次 context Box
分配和一次共享任务池 Arc 克隆。分配失败继续保持这些既有操作的进程级行为。
本函数不入队、不轮询、不唤醒、不阻塞、不执行用户代码、I/O 或 FFI。
Sourcepub fn is_enable_wakeup(&self) -> bool
pub fn is_enable_wakeup(&self) -> bool
检查是否允许唤醒
Sourcepub fn get_inner(&self) -> Option<BoxFuture<'static, O>>
pub fn get_inner(&self) -> Option<BoxFuture<'static, O>>
为外部/手工任务驱动取出装箱的 Future。
本方法在取出 Future 前选择兼容手工调度,因此既有自定义驱动无需新增特征
方法即可保留原有唤醒后调用 push_keep 的行为。本方法不是运行时驱动入口。
当其它驱动拥有 Future 或任务已完成时返回 None。时间复杂度 O(1),不分配;
只获取任务的短 Future 互斥锁,可能与其它 get/set 短暂竞争。不得与本库运行时驱动
并发调用,也不得用于并发轮询同一任务。本操作非纯、非幂等,并转移 Future
所有权。
Sourcepub fn set_inner(&self, inner: Option<BoxFuture<'static, O>>)
pub fn set_inner(&self, inner: Option<BoxFuture<'static, O>>)
为外部/手工任务驱动替换装箱的 Future。
本方法选择兼容手工调度,也允许显式复用已完成的低层任务,从而保留旧公开 get/set
能力。运行时所有的 Pending 恢复使用私有辅助函数,仍保持托管。复用已完成任务
前,手工驱动必须回收全部旧唤醒器;在保留的兼容手工契约下,旧唤醒器否则可能
把替换后的 Future 入队。
时间复杂度 O(1),除调用方拥有的装箱值外不分配;只获取短 Future 互斥锁,不轮询、 不入队也不唤醒。本操作非纯且非幂等。被替换的 Future 会先移出互斥锁临界区, 再在调用线程析构,因此其析构函数不能在持有 Future 锁时重入本任务。
pub fn exist_context(&self) -> bool
pub fn get_context<C: Send + 'static>(&self) -> Option<&C>
pub fn get_context_mut<C: Send + 'static>(&self) -> Option<&mut C>
pub fn set_context<C: Send + 'static>(&self, new: C)
pub fn get_pool(&self) -> &P
Trait Implementations§
Source§impl<P: AsyncTaskPoolExt<O> + AsyncTaskPool<O, Pool = P>, O: Default + 'static> ArcWake for AsyncTask<P, O>
impl<P: AsyncTaskPoolExt<O> + AsyncTaskPool<O, Pool = P>, O: Default + 'static> ArcWake for AsyncTask<P, O>
Source§fn wake_by_ref(arc_self: &Arc<Self>)
fn wake_by_ref(arc_self: &Arc<Self>)
发布一个可运行义务,并在需要时调度任务。
托管任务在已入队或运行时会合并重复唤醒。使空闲任务转为已调度状态的唤醒
准确执行一次 Arc 克隆、一次 push_keep,并且最多通知一个工作线程。运行中
的任务只记录延期调度;当前轮询所有者在恢复返回 Pending 的 Future 后入队。
对已完成任务的唤醒是空操作。
无竞争时的状态处理为 O(1) 且不新增分配;push_keep 继续服从具体任务池既有的
时间、容量和扩容成本。该路径不访问 Future 互斥锁,不阻塞等待,不执行用户回调、
I/O 或 FFI。无锁比较并交换循环不具备无等待性,在竞争状态持续推进时可能重试。
与修改前相同,为保证运行时活性,任务池的 push_keep 必须能够接受可运行任务。