4 个版本
0.2.1 | 2023年10月15日 |
---|---|
0.2.0 | 2023年8月30日 |
0.1.1 | 2023年4月16日 |
0.1.0 | 2023年4月16日 |
在 GUI 中排名 471
每月下载量 34
220KB
4K SLoC
async-winit
像您一直想要的异步运行时一样使用 winit
。
winit
实际上是异步的,这与普遍看法相反;它只是不是 async
。它使用事件循环来处理事件,这对于某些情况来说是很好的,但对于其他情况则不然。 winit
的维护者将这种类型的事件循环称为“穷人版的 async
”;一个不是 async
但仍然是异步的系统。
这个 crate 在这个事件循环之上构建了一个 async
接口。
示例
考虑以下 winit
程序,它创建一个窗口并在窗口大小改变时打印窗口大小
use winit::event::{Event, WindowEvent};
use winit::event_loop::EventLoop;
use winit::window::Window;
fn main2(evl: EventLoop<()>) {
let mut window = None;
evl.run(move |event, elwt, flow| {
match event {
Event::Resumed => {
// Application is active; create a window.
window = Some(Window::new(elwt).unwrap());
},
Event::Suspended => {
// Application is inactive; destroy the window.
window = None;
},
Event::WindowEvent { event, .. } => match event {
WindowEvent::CloseRequested => {
// Window is closed; exit the application.
flow.set_exit();
},
WindowEvent::Resized(size) => {
println!("{:?}", size);
}
_ => {},
},
_ => {},
}
});
}
fn main() {
# return;
let evl = EventLoop::new();
main2(evl);
}
这种策略有点冗长。现在,比较一下等效的 async-winit
程序
use async_winit::event_loop::EventLoop;
use async_winit::window::Window;
use async_winit::ThreadUnsafe;
use futures_lite::prelude::*;
fn main2(evl: EventLoop<ThreadUnsafe>) {
let window_target = evl.window_target().clone();
evl.block_on(async move {
loop {
// Wait for the application to be active.
window_target.resumed().await;
// Create a window.
let window = Window::<ThreadUnsafe>::new().await.unwrap();
// Print the size of the window when it is resized.
let print_size = async {
window
.resized()
.wait()
.for_each(|size| {
println!("{:?}", size);
})
.await;
true
};
// Wait until the window is closed.
let close = async {
window.close_requested().wait().await;
println!("Close");
true
};
// Wait until the application is suspended.
let suspend = async {
window_target.suspended().wait().await;
false
};
// Run all of these at once.
let needs_exit = print_size.or(close).or(suspend).await;
// If we need to exit, exit. Otherwise, loop again, destroying the window.
if needs_exit {
window_target.exit().await;
} else {
drop(window);
}
}
});
}
fn main() {
# return;
let evl = EventLoop::new();
main2(evl);
}
在我看来,更简洁的 async
风格更容易阅读和理解。您的体验可能不同。
优点
- 在许多情况下,将程序视为异步任务可能比将其视为事件循环更有意义。
- 您不需要将所有内容都绑定到
EventLoopWindowTarget
;例如,Window::new()
和其他函数不需要参数,并且只要某个地方有一个EventLoop
在运行,就可以在任何地方调用它们。 - 您可以使用
async
生态系统充分发挥其潜力。
缺点
- 使用
async-winit
会涉及相当数量的开销。这是因为async-winit
是基于winit
构建的,而winit
又是基于其事件循环构建的。这意味着async-winit
必须在async
和winit
的事件循环之间进行转换,这不是免费的。 async-winit
不像winit
那样底层。这意味着您不能做所有可以用winit
做的事情。- 例如,数据不能在各个任务之间进行可变共享。在简单情况下,这可以通过
RefCell
容易地解决,但仍需要额外的思考来处理共享状态。
- 例如,数据不能在各个任务之间进行可变共享。在简单情况下,这可以通过
致谢
async-winit
由 John Nunley (@notgull) 创建。
此项目在很大程度上基于 Stjepan Glavina 等人编写的 async-io
,以及 Pierre Kreiger 等人编写的 winit
。
许可证
async-winit
是自由软件:您可以在以下许可证的条款下重新分发它并/或修改它:
- 由自由软件基金会发布的 GNU Lesser General Public License 的第 3 版或更高版本。
- 由 Mozilla 基金会发布的 Mozilla Public License 第 2 版。
async-winit
的分发是为了希望它将是有用的,但没有任何保证;甚至没有关于适销性和针对特定目的的适合性的暗示保证。有关更多详细信息,请参阅 GNU Lesser General Public License 或 Mozilla Public License。
您应已收到与 async-winit
一起提供的 GNU Lesser General Public License 和 Mozilla Public License 的副本。如果没有,请参阅 https://www.gnu.org/licenses/。
依赖项
~3–17MB
~179K SLoC