16 个版本
0.5.0-deprecated.1 | 2020 年 12 月 8 日 |
---|---|
0.3.4 | 2019 年 10 月 11 日 |
0.3.0 | 2019 年 8 月 2 日 |
0.2.1 | 2019 年 7 月 19 日 |
0.1.7 | 2019 年 7 月 11 日 |
#51 在 #worker-thread
每月 47 次下载
60KB
752 代码行
async_runtime
用于全局生成 futures 的轻量级运行时。
已弃用:这个包已很久没有更新。它需要重写,但结果证明,大多数人更感兴趣的是基于参数的方法,而不是全局执行器方法。在此期间,我发布了 async_executors 和 async_nursery,允许库在不设置全局执行器的情况下选择执行器。还有一个名为 agnostik 的包,功能大致相同。我坚信这是更好的设计,并且自那以后就没有人对全局执行器解决方案提出需求。因此,除非有严重需求,否则我不会更新这个包。
async_runtime
的目的是使生成和运行 futures 更加方便。它允许库作者调用 rt::spawn( future );
,而不必获取 T: Executor
,同时让客户端代码决定使用哪种类型的执行器。它避免了仅仅因为想使用几个提供异步接口的库,而这些库都依赖于它们最喜欢的运行时,就必须引入整个网络栈/反应堆。 async_runtime
努力保持快速和轻量。
一些关键功能
- 宏属性将异步 fn 转换为同步 fn(可以在主程序、测试或任意异步 fn 上使用)
- 尽量做到一件事并做好(不引入网络/计时依赖)
- 支持各种执行器,包括允许生成
!Send
futures 的单线程执行器。 - 轻量级,依赖很少
- 库作者可以生成 futures,应用作者可以决定每个线程使用的执行器。
- WASM支持(这意味着编译在WASM上的库不需要任何特定代码,只需使用
rt::spawn
即可,与同步代码一样)
目录
安装
使用cargo add:cargo add async_runtime
dependencies:
async_runtime: { version: ^0.4, package: naja_async_runtime }
使用原始Cargo.toml
[dependencies]
async_runtime = { version = "^0.4", package = "naja_async_runtime" }
最低要求的rustc版本:1.39。
升级
升级时,请查看变更日志。
功能
这些功能启用额外功能
宏
:将异步fn转换为同步fn的proc宏属性。juliex
:juliex执行器。async_std
:async-std执行器。localpool
:localpool。bindgen
:由wasm-bindgen支持的执行器。
**注意**:对于库作者。您不应该在async_runtime
上启用任何功能。线程级别的执行器由应用程序开发人员选择(例外:您的库正在创建线程)。
依赖项
这个crate有一些依赖项。Cargo会自动为您处理依赖项,但请注意,当您是应用程序开发人员时,您必须至少启用一个执行器,并且可能需要启用宏
功能。
用法
基本概念是这样的。当您创建一个线程时,您调用init
来决定哪个执行器将用于线程中对spawn
及其朋友的调用。async_runtime
确保线程池中的工作线程被设置为在同一个线程池中继续孵化。这个库中的所有顶级函数都将根据选择的执行器正确工作。一个例外是以_local
结尾的函数。这些在线程池中不可用,并将返回错误。
如果在一个没有选择执行器的线程上调用spawn
*,将返回错误。
可用的执行器
**警告**:一些执行器有特定的模块(如rt::localpool
),这些模块提供了特定于该执行器的功能。这些存在两个原因
- 不同支持执行器的API不同。并不总是能够在它们之上提供统一的API。为了避免丢失功能,我们在这些模块中提供这些功能。
- 有时提供统一的API会带来开销,例如,将返回类型装箱(
rt::spawn_handle
)。由于async-std提供了JoinHandle
,因此有async_std::spawn_handle
来恢复该功能,而不是装箱变体。在其他执行器上,您可以使用futures库中的remote_handle
来避免装箱。
LocalPool
- 功能:
localpool
,在非WASM目标上默认启用 - 属性:
#[ rt::localpool ]
- 配置:
rt::Config::LocalPool
- 目标:不在WASM上
- 类型:单线程
- 提供者: futures::executor::LocalPool
LocalPool 执行器作为一个单线程执行器,具有特定的设计,您应该注意。如果它在创建未来后立即轮询未来,则线程将被此操作占用,调用 spawn 的代码将无法立即返回。因此,首先进行创建然后调用阻塞方法以运行执行器。
执行器上有四个可用的方法来运行它
在这里,我不会详细介绍这些函数的功能,请查看它们的文档。目前 async_runtime 只暴露了这些函数中的 run
函数。如果您遇到需要访问其他三个函数的特定问题,请提交一个问题。
Bindgen
- 特性:
Bindgen
,在 WASM 目标上默认启用 - 属性:
#[ rt::bindgen ]
- 配置:
rt::Config::Bindgen
- 目标:仅限于 WASM
- 类型:单线程
- 提供者: wasm-bingen-futures
目前 WASM 上可用的唯一执行器。它像一个多线程执行器一样运行,创建的未来将立即开始轮询,无需调用 run
方法来启动执行器。
Juliex
- 特性:
juliex
- 属性:
#[ rt::juliex ]
- 配置:
rt::Config::Juliex
- 目标:不在WASM上
- 类型:线程池
- 提供者:juliex
这是一个线程池。创建的工作线程将自动将 juliex 设置为线程执行器。目前无法通过 API async_runtime
暴露来更改。未来将立即轮询。
如果您有一个阻塞在顶级未来上,或者被宏属性等待的未来,一旦该未来完成,程序将结束,即使线程池中还有未完成的任务。
async_runtime
提供了 spawn_handle
方法来等待您的未来,但需要将返回的句柄装箱。否则,您可以添加自己的同步,例如通道或来自 futures 库的 join_all
,以等待您的任务。futures 库还提供了 remote_handle
。
AsyncStd
- 特性:
async_std
- 属性:
#[ rt::async_std ]
- 配置:
rt::Config::AsyncStd
- 目标:不在WASM上
- 类型:线程池
- 提供者: async-std
这是一个线程池。创建的工作线程不能自动将 AsyncStd 设置为默认执行器。这意味着 rt::spawn
将有一些开销来确保工作线程正确初始化。
警告:async-std 没有可选依赖项,因此您将拉入所有依赖项,包括网络库、mio 等,如果您不使用它们,这可能会导致膨胀。
将立即轮询将来的事件。如果您有一个顶级未来,该未来被阻塞,或者正在等待宏属性,那么一旦该未来完成,程序将结束,即使线程池中仍有未完成的任务。
async_runtime
提供了 spawn_handle
方法来等待您的未来,但需要将返回的句柄装箱。否则,您可以添加自己的同步,例如通道或来自 futures 库的 join_all
,以等待您的任务。futures 库还提供了 remote_handle
。
block_on
- 功能:无功能,始终可用
- 属性:N/A
- 配置:N/A
- 目标:不在WASM上
- 类型:阻塞当前线程
- 提供者:
futures::executor::block_on
请阅读[block_on]的文档。
示例
请查看存储库的示例目录。
use async_runtime as rt;
// in library code:
//
fn do_something_in_parallel() -> Result<(), RtErr>
{
rt::spawn( async
{
println!( "I'm running in async context" );
})
}
// In client code we might decide that this runs in a LocalPool, instead of a threadpool:
//
[ rt::localpool ]
//
fn main()
{
// Please look at the documentation for spawn for the possible errors here.
//
do_something_in_parallel().expect( "Spawn futures" );
}
// In this example we run a bunch of tasks in parallel. To verify that
// they run on different threads we make them all sleep for a second and
// measure the time passed when they finish. If they run on a threadpool
// time passed for all of them should be around 1 second.
#![ feature( duration_constants ) ]
use
{
async_runtime as rt,
std :: { time::{ Duration, Instant }, thread::sleep } ,
futures :: { future::{ FutureExt, join_all } } ,
};
#[ rt::juliex ]
//
async fn main()
{
let start = Instant::now();
let mut tasks = Vec::new();
for i in 0..4
{
// There isn't currently a convenient way to run tasks on a threadpool until all tasks have
// finished, or until some shutdown signal is given.
//
// This is one of the ways tasks can synchronize and wait on eachother. Another way is to wait
// on channels.
//
let (fut, handle) = async move
{
sleep( Duration::SECOND );
println!( "Time elapsed at task {} end: {} second(s).", i, start.elapsed().as_secs() );
}.remote_handle();
rt::spawn( fut ).expect( "spawn task" );
tasks.push( handle );
}
join_all( tasks ).await;
}
Wasm
要在 wasm 中使用该包,请查看存储库的示例目录中的示例。
在 WASM 上可用的唯一执行器目前是 bindgen。
API
API 文档可以在docs.rs上找到。
贡献
此存储库接受贡献。可以通过 GitHub issues 提交想法、问题、功能请求和错误报告。
欢迎在 GitHub 上提交拉取请求。通过提交拉取请求,您同意您的代码可能会被修改和重新格式化,以符合项目编码风格或改进实现。如果您不希望进行可能会被拒绝的工作,请在提交拉取请求之前讨论您想看到的内容。
请针对 dev 分支提交拉取请求。
行为准则
在公民行为准则第4点“不可接受的行为”中描述的任何行为都不受欢迎,并可能导致您被禁止。如果包括维护者和项目管理员在内的任何人未能尊重这些/您的限制,您有权指出。
许可证
依赖项
~1–15MB
~160K SLoC