42个版本
0.14.0 | 2024年6月4日 |
---|---|
0.13.0 | 2024年3月1日 |
0.12.4 | 2024年1月15日 |
0.12.3 | 2023年10月10日 |
0.4.2 | 2018年11月15日 |
#41 in 异步
468,070 每月下载量
用于 1,202 个crates (17 直接)
290KB
6K SLoC
calloop
Calloop,一个基于回调的事件循环
该crate提供了一种名为EventLoop
的类型,它是在轮询系统上的一个小型抽象。与其他传统的Rust事件循环相比,此crate的主要区别在于它基于回调:您可以注册多个事件源,每个事件源都与一个回调闭包相关联,该闭包将在关联的事件源生成事件时被调用。
因此,此事件循环的主要用途是用于那些预期将大部分时间用于等待事件,并希望以便宜和方便的方式进行的应用程序。它不适合大规模高性能IO。
如何使用
以下是一个快速使用calloop的示例。有关更深入的教程,请参阅calloop book。
对于简单的使用,您可以直接将事件源和回调添加到事件循环中。例如,以下是一个在五秒后退出的可运行程序
use calloop::{timer::{Timer, TimeoutAction}, EventLoop, LoopSignal};
fn main() {
// Create the event loop. The loop is parameterised by the kind of shared
// data you want the callbacks to use. In this case, we want to be able to
// stop the loop when the timer fires, so we provide the loop with a
// LoopSignal, which has the ability to stop the loop from within events. We
// just annotate the type here; the actual data is provided later in the
// run() call.
let mut event_loop: EventLoop<LoopSignal> =
EventLoop::try_new().expect("Failed to initialize the event loop!");
// Retrieve a handle. It is used to insert new sources into the event loop
// It can be cloned, allowing you to insert sources from within source
// callbacks.
let handle = event_loop.handle();
// Create our event source, a timer, that will expire in 2 seconds
let source = Timer::from_duration(std::time::Duration::from_secs(2));
// Inserting an event source takes this general form. It can also be done
// from within the callback of another event source.
handle
.insert_source(
// a type which implements the EventSource trait
source,
// a callback that is invoked whenever this source generates an event
|event, _metadata, shared_data| {
// This callback is given 3 values:
// - the event generated by the source (in our case, timer events are the Instant
// representing the deadline for which it has fired)
// - &mut access to some metadata, specific to the event source (in our case, a
// timer handle)
// - &mut access to the global shared data that was passed to EventLoop::run or
// EventLoop::dispatch (in our case, a LoopSignal object to stop the loop)
//
// The return type is just () because nothing uses it. Some
// sources will expect a Result of some kind instead.
println!("Timeout for {:?} expired!", event);
// notify the event loop to stop running using the signal in the shared data
// (see below)
shared_data.stop();
// The timer event source requires us to return a TimeoutAction to
// specify if the timer should be rescheduled. In our case we just drop it.
TimeoutAction::Drop
},
)
.expect("Failed to insert event source!");
// Create the shared data for our loop.
let mut shared_data = event_loop.get_signal();
// Actually run the event loop. This will dispatch received events to their
// callbacks, waiting at most 20ms for new events between each invocation of
// the provided callback (pass None for the timeout argument if you want to
// wait indefinitely between events).
//
// This is where we pass the *value* of the shared data, as a mutable
// reference that will be forwarded to all your callbacks, allowing them to
// share some state
event_loop
.run(
std::time::Duration::from_millis(20),
&mut shared_data,
|_shared_data| {
// Finally, this is where you can insert the processing you need
// to do do between each waiting event eg. drawing logic if
// you're doing a GUI app.
},
)
.expect("Error during event loop!");
}
事件源类型
事件循环由操作系统提供的轮询选择器(Linux上的epoll)支持。
此crate还提供了一些常见事件源的适配器,例如
- MPSC通道
- 定时器
- Linux上的Unix信号
以及由文件描述符支持的通用对象。
还可以插入“空闲”回调。这些回调代表需要在某个时候执行的计算,但不如处理事件紧急。这些回调被存储,然后在EventLoop::dispatch
期间执行,一旦处理完所有来自源的事件。
Async/Await兼容性
calloop
可以与futures一起使用,既可以用作执行器,也可以用于监控异步IO。
激活 executor
货物功能将添加 futures
模块,该模块提供了一个可以将作为另一个 EventSource
插入到 EventLoop
的未来执行器。
可以通过 LoopHandle::adapt_io
方法使 IO 对象异步感知。使用这些对象唤醒未来的处理由相关的 EventLoop
直接处理。
自定义事件源
您可以通过实现 EventSource
特性来创建自定义事件源,并将其插入事件循环。这可以通过直接从感兴趣源的文件描述符执行,或者通过包装其他事件源并进一步处理其事件来实现。一个 EventSource
可以注册多个文件描述符并将它们聚合。
平台支持
目前,calloop 在 Linux、FreeBSD 和 macOS 上进行了测试。
以下平台在编译时也启用了,但未进行测试:Android、NetBSD、OpenBSD、DragonFlyBSD。
基于它们与测试平台具有相同的轮询机制的事实,这些平台 应该 能够正常工作,但仍可能存在一些细微的错误。
最小安全 Rust 版本
此存储库当前的最小安全 Rust 版本 (MSRV) 是 Rust 1.63。然而,当启用 signals
功能时,它将升级到 nix
的 MSRV。在撰写本文时,这是 Rust 1.69。
在 calloop
v1.0 之前,MSRV 的升级将导致修订版本的升级。一旦发布 calloop
v1.0,MSRV 的升级将导致次要版本的升级。简而言之,MSRV 的升级不被视为破坏性更改。
作为一个 暂定的 策略,基本 MSRV 不会超过由 Debian Stable 提供的当前 Rust 版本[链接]。在撰写本文时,此 Rust 版本为 1.63。然而,在主要生态系统发生重大变化或存在安全漏洞的情况下,MSRV 可能会进一步升级。
许可证:MIT
依赖项
~2–11MB
~128K SLoC